于Java好的方面是它有内置的写多线程的支持Java的设计者知道多线程编程的价值所以聪明决定在Java的核心部分就决定直接支持线程在第章并发存取对象和变量就阐述了在Java语言中synchronized关键字如何被用来锁住对象和类来控制并发存取数据Thread和ThreadGroup类就在javalang包的核心API中通过wait( ) notify( ) 方法的支持Java中所有类的父类Object具有线程间通信的能力即使当前操作系统不支持线程概念一个写好的JVM也可以模拟多线程环境在Java中线程的支持不是事后的而是从一开始设计时就包括进来的
一个简单的两个线程例子
概述
这章展示了创建并在一个小的Java应用中运行线程是如何简单第一个线程是总是有JVM创建的main线程该线程开始运行程序这个主线程然后创建第二个线程每个线程将在控制台打印各自信息以此来证明他们好像以同步方式运行
这章中例子创建一个线程的步骤如下
继承javalangThread类
在继承Thread的子类中重写run( )方法
创建这个新类的实例
调用该实例的start( )方法
继承javalangthread类
在JavaVM中每个线程与javalangThread类的一个实例想关联这些Thread对象作为与底层操作系统线程交互的接口通过类中的方法可以对线程进行开始停止中断命名设置优先级和查询有关当前状态
注意有两种方式可创建一个允许线程运行与其中的类一种方式是继承Thread类另一种是继承任意类并且实现Runnable接口为了说明的原因继承Thread类是最简单的方法本书开始就是用该方法在实际中实现Runnable接口工作地更好些
在这个例子中创建一个新线程的第一步是继承javalangThread类
Java代码
public class TwoThread extends Thread {
//
}
TwoThread子类是一个(ISA) Thread并且继承了父类的protected 和public成员TwoThread除了从父类中继承的其他行为之外它还能被开始停止中断命名设置优先级以及查询线程当前状态
重写run()方法
继承Thread类之后下一步就是重写run()方法因为Thread类中方法什么也没做
Public void run() { }
当一个新线程开始运行进入该线程的入口就是run()方法run()中的第一条语句就是新线程执行的第一条语句线程执行的每条语句都包含在run()方法中或包含在被run()方法直接或间接调用的其他方法中从run()被调用之前到run()返回新线程被认为是活着的run()返回之后线程就死掉了当一个线程死了之后不能重新开始
在本章的例子中run()方法被重写为迭代次并且每次打印New thread信息
Java代码
public void run() {
for ( int i = ; i < ; i++ ) {
Systemoutprintln(New thread);
}
}
循环完成之后线程从run()方法返回然后安静死掉
创建一个新线程 Spawning a New Thread
新线程从已经运行的线程来创建首先构造一个新Thread实例在此例中一个新TwoThread对象将正好因为TwoThread ISA Thread
TwoThread tt = new TwoThread();
下一步是调用start()方法准备开始执行线程(start()从Thread继承而来)
ttstart();
start()调用后立即返回不需要等待其他线程开始执行在start()中父线程异步地从JavaVM中给线程调度程序发出信号告诉它只要它方便其他线程可以开始执行了在未来某个不可预期的时间里其他线程将被激活并调用Thread对象的run()方法(在该例中是指TwoThread中实现的重写方法run())与此同时原来的线程继续执行start()方法后面的语句
两个线程并发独立地运行在一个多处理器的机器上这两个线程可能在同一时刻真正都在运行各自运行在自己的处理器上
一个更常见的情况是只有一个处理器JavaVM和操作系统共同工作来短时间调度每个线程当其他线程被冻结等待处理器的下一次机会时每个线程就得到一次运行的机会这种在线程之间的上下文切换是非常快的给人一种同时执行的假象
提示一个新创建的线程可能在start()被调用之后的任何时间开始执行(进入run()方法)这意味着start()方法之后的任何语句被执行之前原来线程都可能被换出(swapped out)
假如原来的线程正在执行下面的代码
stmt();
ttstart();
新线程有一个run()方法如下
Java代码
public void run() {
stmtA();
stmtB();
}
stmt();
处理器中实际执行的语句顺序可能是stmt() ttstart() stmt() stmtA() and stmtB()也可能是stmt() ttstart() stmtA() stmtB() and stmt()也许还可能是另外一种顺序
重要的是要记住尽管每个线程将执行各自语句的顺序是已知和简单的但是实际运行在处理器上的语句却是不确定的对于程序的正确性而言没有一种特殊的顺序可以依赖
把所有放在一起
TwoThreadjava shown in Listing
Listing TwoThreadjava—The Complete Code for the TwoThread Example
Java代码
: public class TwoThread extends Thread {
: public void run() {
: for ( int i = ; i < ; i++ ) {
: Systemoutprintln(New thread);
: }
: }
:
: public static void main(String[] args) {
: TwoThread tt = new TwoThread();
: ttstart();
:
: for ( int i = ; i < ; i++ ) {
: Systemoutprintln(Main thread);
: }
: }
: }