基础篇(二)
在进入java平台的线程对象之前,基于基础知识(一)的一些问题,我先插入两个基本概念.
[线程的并发与并行]
在单CPU系统中,系统调度在某一时刻只能让一个线程运行,虽然这种调试机制有多种形式
(大多数是时间片轮巡为主),但无论如何,要通过不断切换需要运行的线程让其运行的方式
就叫并发(concurrent).
而在多CPU系统中,可以让两个以上的线程同时运行,这种可以同时让两个以上线程同时运行
的方式叫做并行(parallel).
在上面包括以后的所有论述中,请各位朋友谅解,我无法用最准确的词语来定义储如并发和
并行这类术语,但我以我的经验能通俗地告诉大家它是怎么一回事,如果您看到我说的一些
"标准"文档上说的不一样,只要意思一致,那您就不要挑刺了.
[JAVA线程对象]
现在我们来开始考察JAVA中线程对象.
在JAVA中,要开始一个线程,有两种方式.一是直接调用Thread实例的start()方法,二是
将Runable实例传给一个Thread实例然后调用它的start()方法.
在基础知识(一)中已经说过,线程对象和线程是两个完全不同的概念.这里我们再次
深入一下,生成一个线程的实例,并不代表启动了线程.而启动线程是说在某个线程对象上启动
了该实例对应的线程,当该线程结束后,并不会就立即消失.
对于从很多书籍上可以看到的基础知识我就不用多说了.既然是基础知识,我也着重
于从普通文档上读不到的内容.
所以本节我重点要说的是两种线程对象产生线程方式的区别.
class MyThread extends Thread{
public int x = 0;
public void run(){
for(int i=0;i<100;i++){
try{
Thread.sleep(10);
}catch(Exception e){}
System.out.println(x++);
}
}
}
如果我们生成MyThread的一个实例,然后调用它的start();方法,那么就产生了这个实例对应
的线程:
public class Test {
public static void main(String[] args) throws Exception{
MyThread mt = new MyThread();
mt.start();
}
}
不用说,最终会打印出0到99,现在我们稍微玩一点花样:
public class Test {
public static void main(String[] args) throws Exception{
MyThread mt = new MyThread();
mt.start();
System.out.println(101);
}
}
也不用说,在基础知识(一)中我们知道由于单CPU的原因,一般会先打印101,然后打印
0到99.不过我们可以控制线程让它按我们的意思来运行:
public class Test {
public static void main(String[] args) throws Exception{
MyThread mt = new MyThread();
mt.start();
mt.join();
System.out.println(101);
}
}
好了,我们终于看到,mt实例对应的线程(假如我有时说mt线程请你不要怪我,不过我尽量不这么说)
在运行完成后,主线程才打印101.因为我们让主当前线程(这里是主线程)等待mt线程的运行结束.
"在线程对象a上调用join()方法,就是让当前正在执行的线程等待线程对象a对应的线程运行完成后
才继续运行." 请大家一定要深刻理解并熟记这句话,而我这里引出这个知识点的目的是为了让你继
续看下面的例子:
public class Test {
public static void main(String[] args) throws Exception{
MyThread mt = new MyThread();
mt.start();
mt.join();
Thread.sleep(3000);
mt.start();
}
}
当线程对象mt运行完成后,我们让主线程休息一下,然后我们再次在这个线程对象上启动线程.结果我
们看到:
Exception in thread "main" java.lang.IllegalThreadStateException
也就是这种线程对象一时运行一次完成后,它就再也不能运行第二次了.
我们可以看一下它有具体实现:
public synchronized void start() {
if (started)
throw new IllegalThreadStateException();
started = true;
group.add(this);
start0();
}
一个Thread的实例一旦调用start()方法,这个实例的started标记就标记为true,事实中不管这个线程
后来有没有执行到底,只要调用了一次start()就再也没有机会运行了,这意味着:
[通过Thread实例的start(),一个Thread的实例只能产生一个线程]
那么如果要在一个实例上产生多个线程(多个线程共同访问同一实例的一些共同资源),我们应该如何做呢?这就是Runnable
接口给我们带来的伟大的功能.
class R implements Runnable{
private int x = 0;
public void run(){
for(int i=0;i<100;i++){
try{
Thread.sleep(10);
}catch(Exception e){}
System.out.println(x++);
}
}
}
正如它的名字一样,Runnable的实例是可运行的,但它自己并不能直接运行,它需要被Thread对象来
包装才行运行:
public class Test {
public static void main(String[] args) throws Exception{
new Thread(new R()).start();
}
}
当然这个结果和mt.start()没有什么区别.但如果我们把一个Runnable实例给Thread对象多次包装,我
们就可以看到它们实际是在同一实例上启动线程:
public class Test {
public static void main(String[] args) throws Exception{
R r = new R();
for(int i=0;i<10;i++)
new Thread(r).start();
}
}
x是实例对象,但结果是x被加到了999,说明这10个线程是在同一个r对象上运行的.请大家注意,因为这个
例子是在单CPU上运行的,所以没有对多个线程同时操作共同的对象进行同步.这里是为了说明的方便而
简化了同步,而真正的环境中你无法预知程序会在什么环境下运行,所以一定要考虑同步.
到这里我们做一个完整的例子来说明线程产生的方式不同而生成的线程的区别:
package debug;
import java.io.*;
import java.lang.Thread;
class MyThread extends Thread{
public int x = 0;
public void run(){
System.out.println(++x);
}
}
class R implements Runnable{
private int x = 0;
public void run(){
System.out.println(++x);
}
}
public class Test {
public static void main(String[] args) throws Exception{
for(int i=0;i<10;i++){
Thread t = new MyThread();
t.start();
}
Thread.sleep(10000);//让上面的线程运行完成
R r = new R();
for(int i=0;i<10;i++){
Thread t = new Thread(r);
t.start();
}
}
}
上面10个线程对象产生的10个线程运行时打印了10次1.
下面10个线程对象产生的10个线程运行时打印了1到10.
我们把下面的10个线程称为同一实例(Runnable实例)的多个线程.
下节我们将研究线程对象方法,还是那句话,一般文档中可以读到的内容我不会介绍太多
转载自: 我认为最懂线程的人
http://blog.csdn.net/axman/article/details/420892
分享到:
相关推荐
5. **多线程**:Java提供了内置的多线程支持,通过Thread类和Runnable接口可以创建并管理线程。理解线程同步(如synchronized关键字和Lock接口)以及并发工具类(如ExecutorService和Future)是处理并发问题的关键。...
Java提供了Thread类以及Runnable接口来支持多线程编程。 3. **IO流**: - **输入输出流**:Java的IO流用于数据的读写,例如InputStream和OutputStream用于字节流,而Reader和Writer处理字符流。在网络通信中,我们...
Chap19:JNI编程系列之基础篇... 148 System.loadLibrary("HelloWorld"); 149 JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject); 150 Chap20:JNI编程系列之中级篇(上)... 151 1. Java基本...
《深入理解Java虚拟机》、《并发编程的艺术》、《Java多线程核心编程艺术》、《Java8函数式编程》、《Redis设计与实现》、《RocketMQ技术内幕》、《Spring技术内幕》、《Spring源码深度解析》、《剑指Offer》、...
- 《深入理解Java虚拟机:JVM高级特性与最佳实践》:周志明的书,深入讲解JVM内存模型和多线程,对并发编程有较大帮助。 - 《Java EE 6 权威指南.基础篇.Basic concepts》:尽管现代开发更多依赖Spring等框架,...
1. `讨论CString线程安全性问题(内存泄漏) - 专注于股票类开发 和 电子海图开发 - C++博客.htm`: 这篇文章可能探讨了在多线程环境下使用CString时,由于同步问题导致的内存泄露。 2. `Isolating memory leaks - ...
Java作为一门广泛使用的编程语言,其面试题涵盖了众多的知识领域,包括基础语法、面向对象、集合框架、多线程、异常处理、IO流、网络编程、设计模式、JVM优化、数据库操作等。以下是一些Java面试中常被问到的知识点...
会 Java 的人越来越多,但是一直徘徊在语言层次的程序员不在少数,真正掌握 Java 中接口或抽象类的应用不是很多,大家 经常以那些技术只适合大型项目为由,避开或忽略它们,实际中,Java 的接口或抽象类是真正体现 ...
学习WinSocket全双工通信,不仅需要理解上述步骤,还要熟悉错误处理、多线程或多路复用技术(如select、poll、epoll),以提高服务器处理并发连接的能力。此外,深入理解TCP的工作原理,包括滑动窗口、拥塞控制等,...
例如,单线程模型适合简单应用,而多线程模型可以处理高并发情况。 从压缩包文件的名称可以看出,其中包含的内容涵盖了MINA的快速开发、参考手册、使用手记和线程模型配置等多个方面: - **基于MINA框架快速开发...
同时,具备C++编程基础,因为OGRE主要用C++编写,且多数示例代码也会采用C++。熟悉面向对象编程思想将有助于更好地理解OGRE的设计模式。 **教程的由来** 教程的创作源于作者们在实际开发中的需求和经验积累,他们...
微信公众号目录算法Java虚拟机春天SpringMVC高并发架构基石-缓存网络篇架构其他主意书单《 Java编程思想(第4版)》-Java领域的圣经,建议稍微有点基础后阅读。不推荐初学者阅读,小心被劝退《深入理解Java虚拟机》-...
它的效率特性包括优化的渲染管道,支持硬件加速,以及对多线程处理的良好支持。此外,OGRE兼容多种平台,包括Windows、Linux、Mac OS X等,并且可以与Direct3D和OpenGL等3D图形API无缝集成。 在3D模型表示方面,...