Presentation is loading. Please wait.

Presentation is loading. Please wait.

Java Programming Spring, 2010

Similar presentations


Presentation on theme: "Java Programming Spring, 2010"— Presentation transcript:

1 Java Programming Spring, 2010

2 Java 的多线程机制 线程简介 线程的创建及运行 线程同步控制

3 Thread(线程)简介 多线程机制是Java语言的又一重要特征,使用多线程技术可以使系统同时运行多个执行体,加快程序的响应时间,提高计算机资源的利用率。 使用多线程技术可以提高整个应用系统的性能。

4 Thread(线程)简介 程序、进程、线程
程序(Program)是静态的一段代码。 多线程程序:一可以同时运行多个相对独立的线程的程序。 一个运行中的程序称为一个进程(Process)。 进程是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,这个过程也是进程本身从产生、发展至消亡的过程。 Thread(线程)是程序中的一条执行路径。 一个进程在其执行过程中,可以产生多个线程,形成多条执行路径,每条路径,即每个线程也有它自身的产生、存在和消亡的过程,也是一个动态的概念。

5 线程与进程的区别: 多个进程的内部数据和状态都是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能互相影响.
每个进程都有一段专用的内存区域,而线程间可以共享相同的内存单元(包括代码与数据),并利用这些共享单元来实现数据交换、实时通信与必要的同步操作。

6 Thread(线程)简介 多任务是针对操作系统而言的,代表着操作系统可以同时执行的程序个数;
多线程(Multithreading)是一个程序实现多任务的能力。 多线程是针对一个程序而言的,代表着一个程序内部可以同时执行多个线程,而每个线程可以完成不同的任务。即:允许单个程序创建多个并行执行的线程来完成各自的任务。 例如:浏览器程序就是一个多线程的例子,在浏览器中可以在下载Java小程序或图像的同时滚动页面,在访问新页面时,播放动画和声音,打印文件等。

7 Thread(线程)简介 多线程的任务 传统的进程 文件 各种系统资源 输入输出装置 文件 各种系统资源 输入输出装置 数据区段 数据区段
程序区段 程序区段 同时有数个地方在执行 只有一个地方在执行 多线程的任务 传统的进程

8 Thread(线程)简介 多线程的优势: 在多线程模型中,多个线程共存于同一块内存中,且共享资源。
操作系统将CPU的执行划分为非常小的时间片(time slot),根据一定的规则在不同的线程之间分配,使每个线程都得到执行的机会来处理任务。 多个线程在运行时,系统自动在线程之间进行切换。由于CPU在各个线程之间的切换速度非常快,用户感觉不到,从而认为并行运行。 由于多个线程共存于同一块内存,线程之间的通信非常容易;

9 Thread(线程)的创建 线程类Thread定义在java.lang包中;
Java将线程视为一个对象。线程要么是Thread类的对象,要么是接口Runnable的对象。 创建线程的方式有两种: 通过实现Runnable接口的类来实现。 通过创建Thread类的子类来实现;

10 线程的创建 通过创建Thread类的子类来实现; 通过实现Runnable接口的类来实现。

11 接口Runnable java.lang.Runnable
public interface java.lang.Runnable { public abstract void run(); }

12 java.lang.Thread public class java.lang.Thread
extends java.lang.Object implements java.lang.Runnable { public Thread(); public Thread(Runnable target); public Thread(Runnable target, String name); public Thread(String name); ... public void run(); //来自Runnable接口 public synchronized void start(); public static void sleep(long millis)throws InterruptedException; public static void yield(); public final String getName(); } constructors methods

13 Thread类包含的常量 public static final int MAX_PRIORITY 最大优先级,值是10。
2. public static final int MIN_PRIORITY 最小优先级,值是1。 3. public static final int NORM_PRIORITY 缺省优先级,值是5。

14 Thread类的方法 start( ) run() 使调用该方法的线程开始执行,调用本线程的run()方法。
在本方法内编写运行本线程时需要执行的代码,也是Runnable接口的唯一方法。 当一个线程初始化后,由start()方法来自动调用它,一 旦run()方法返回,本线程也就终止了。

15 Thread类的方法 常用方法: currentThread( ):返回当前运行的线程(Thread)对象,是一个静态的方法。
sleep(int n):使当前运行的线程睡n个毫秒,然后继续执行,也是静态方法。 yield( ):使当前运行的线程放弃执行,切换到其它线程,是一个静态方法。 isAlive( ):判断线程是否处于执行的状态,返回值true表示处于运行状态,false表示已停止。

16 Thread类的方法 stop( ):使线程停止执行,并退出可执行状态。 suspend():使线程暂停执行,不退出可执行态。
setName(String s):赋予线程一个名字。 getName( ):获得调用线程的名字。 getPriority( ):获得调用线程的优先级。 setPriority(int p):设置线程的优先级。 join( ):等待调用该方法的线程终止,若中断了该线程,将抛出异常。

17 创建线程的方法 方法1:通过创建Thread类的子类实现多线程,步骤如下 : 用户自定义线程 1. 定义Thread类的一个子类。
2. 定义子类中的方法run( ),覆盖父类中的方法run( )。 使用线程 3. 创建该子类的一个线程对象。 4. 通过start( )方法启动线程。

18 Extending Thread class
注意:Thread类中的run( )方法具有public属性,覆盖该方法时,前面必须带上public。 class MyThread extends Thread { public void run() //thread body of execution }

19 Create and Execute Thread
MyThread thr1 = new MyThread(); 运行一个线程: thr1.start(); 创建和运行线程(合并): new MyThread().start();

20 Example 1: class MyThread extends Thread { private String name, msg;
public MyThread(String name, String msg) { this.name = name; this.msg = msg; } public void run() { System.out.println(name+" starts its execution"); for (int i = 0; i < 5; i++) { System.out.println(name + " says: " + msg); try { Thread.sleep(5000); } catch (InterruptedException ie) { } System.out.println(name + " finished execution"); 重写run()

21 the threads will run in parallel
Example 1 (cont.) public class test { public static void main(String[] args) { MyThread mt1 = new MyThread("thread1", "ping"); MyThread mt2 = new MyThread("thread2", "pong"); mt1.start(); mt2.start(); } the threads will run in parallel

22 Example 1 (cont.) 输出: 注意: thread1 starts its execution
thread1 says: ping thread2 starts its execution thread2 says: pong thread1 finished execution thread2 finished execution 注意: 一个程序中,多个线程的运行具有不确定性。 线程一旦启动,线程的运行完全由JVM调度程序控制,程序员无法控制它的执行顺序,持续时间也没有保障,运行结果不可预料。

23 使用Runnable接口实现多线程 用继承Thread类的子类或实现Runable接口的类来创建线程无本质区别,但由于Java不支持多重继承,所以如果一个类必须继承另一个非Thread类,此时要实现多线程只能通过实现Runnable接口的方式。

24 创建多线程的方法(续) 1.定义一个实现Runnable接口的类。 方法2:通过接口创建多线程,步骤如下:
2.定义方法run( )。Runnable接口中有一个空的方法run( ),实现它的类必须覆盖此方法。 3.创建该类的一个线程对象,并将该对象作参数,传递给Thread类的构造函数,从而生成Thread类的一个对象。 // 注意这一步! Thread(Runnable target) Thread(Runnable target, String name) 4.通过start( )方法启动线程。

25 Implementing Runnable interface
class MyThread extends ABC implements Runnable { ..... public void run() // thread body of execution } Creating Object: MyThread myObject = new MyThread(); Creating Thread Object: Thread thr1 = new Thread(myObject); Start Execution: thr1.start();

26 Example 2 class MyThread implements Runnable { public void run() {
System.out.println(" this thread is running ... "); } class ThreadEx2 { public static void main(String[] args) { Thread t = new Thread(new MyThread()); t.start(); }

27 main(主)线程 Java应用程序总是从主类的main方法开始执行。
当JVM加载代码,发现main方法之后,就会启动一个线程,这个线程称作“主线程”,该线程负责执行main方法。 在main方法中再创建的线程,就称为主线程中的线程。 如果main方法中没有创建其他的线程,那么当main方法执行完最后一个语句,即main方法返回时,JVM就会结束我们的Java应用程序。 如果main方法中又创建了其他线程,那么JVM就要在主线程和其他线程之间轮流切换,保证每个线程都有机会使用CPU资源。main方法即使执行完最后的语句,JVM也不一定会结束我们的程序,JVM一直要等到主线程中的所有线程都结束之后,才结束我们的Java应用程序。

28 A Multithreaded Program
Main Thread start start start Thread A Thread B Thread C Threads may switch or exchange data/results

29 public static void main(String args[ ]) { String name; int p;
//通过调用Thread.currentThread方法来查看当前运行的是哪一个线程。 class getThreadInfo { public static void main(String args[ ]) { String name; int p; Thread curr =Thread.currentThread( );//获得当前线程 System.out.println("当前线程: "+curr); name=curr.getName( ); //获得当前线程的名称 p=curr.getPriority( ); //获得当前线程的优先级 System.out.println("线程名: "+name); System.out.println("优先级 :"+p);  } 程序输出结果: 当前线程: Thread[main,5,main] 线程名 : main 优先级 :5

30 线程的状态与生命周期 创建 可运行 (就绪) 不可运行 运行中 死亡

31 线程的生命周期

32 Thread myThread = new MyThreadClass( );
线程的状态与生命周期 1.创建状态(new Thread) 当一个线程处于创建状态时,它仅仅是一个空的线程对象,系统不为它分配资源。 Thread myThread = new MyThreadClass( ); 2.可运行状态(就绪, Runnable) myThread.start( ); 其中start()方法产生了运行这个线程所需的系统资源,安排其运行,并调用线程体—run()方法,这样就使得该线程处于可运行(Runnable)状态。 当一个线程处于可运行状态时,系统为这个线程分配了它所需的系统资源,安排运行并调用线程运行方法,这样就使得该线程处于可运行状态。需要注意的是这一状态并不是运行中状态,因为线程也许实际上并未真正运行。

33 线程的状态与生命周期 3. 运行中状态(Running) Java的运行系统调度选中一个可运行状态的线程,该线程占有CPU并转为运行中状态。
4.   不可运行状态(Not Runnable) 不可运行状态也称为阻塞状态(Blocked)。 例如:被人为挂起或需要执行费用时输入输出操作时,将让出CPU,并暂时终止自己的执行,进入阻塞状态。 阻塞时它不能进入排队队列,只有当引用阻塞的原因被消除时,线程才可以转入就绪状态,重新进到线程队列中排队等待CPU资源,以便从原来终止处开始继续运行。

34 线程的状态与生命周期 5. 死亡状态(Dead) 处于死亡状态的线程不具有继续运行的能力。线程死亡的原因有两个:
正常运行的线程完成了它的全部工作,即执行完了run()方法的最后一个语句并退出; 线程被提前强制性地终止,如通过执行stop()终止线程。 线程在各个状态之间的转化及线程生命周期的演进是由系统运行的状况、同时存在的其他线程和线程本身的算法所共同决定的。

35 线程的Priority(优先级) 线程的优先级用数字来表示,范围从1到10,即Thread.MIN_PRIORITY 到 Thread.MAX_PRIORITY。 一个线程的默认优先级是5,即Thread.NORM_PRIORITY; Thread.MIN_PRIORIT、Thread.NORM_PRIORITY、Thread.MAX_PRIORITY 是 Thread类的三个公用静态常量。

36 线程的Priority(优先级) 对应一个新建线程,系统会遵循如下的原则为其指定优先级:
新建线程将继承创建它的父线程的优先级。父线程是指执行创建新线程对象语句的线程,它可能是程序的主线程,也可能是某一个用户自定义的线程。 一般情况下,主线程具有普通优先级。 也可以通过getPriority()方法来获得线程的优先级,也可以通过setPriority()方法来设定线程的优先级。方法定义如下: public final void setPriority(int nwePriority); public final int getPriority( );

37 线程调度模型 Java提供一个线程调度器来监控程序中启动后进入可运行状态的全部线程。
线程调度器按线程的优先级高低选择高优先级线程执行,即:选择处于就绪状态且优先级最高的线程。 如果多个线程具有相同的优先级,它们将被轮流调度。 同时,线程调度是先占式调度,即:如果在当前线程执行过程中,一个更高优先级的线程进入可运行状态,即这个线程立即被调度执行。 注意: 虽然JVM以及操作系统会优先处理优先级别高的线程,但不代表这些线程一定会先完成。设定优先级只能建议系统更快的处理,而不能强制。 程序4验证了Java对多线程的调度方法,但结果还是具有不确定性。

38 class threadTest extends Thread { public threadTest(String str){
// 程序4 class threadTest extends Thread { public threadTest(String str){ super(str); } public void run( ) { try{ Thread.sleep(2); }catch(InterruptedException e) { System.err.println(e.toString( )); System.out.println(getName( )+" " + getPriority( ));

39 注意:该程序的输出结果有可能与上面结果不同。
public class multTheadOne{ public static void main(String agrs[]){ Thread one=new threadTest("one" ); Thread two=new threadTest("two" ); Thread three=new threadTest("three" ); one.setPriority(Thread.MIN_PRIORITY); two.setPriority(Thread.NORM_PRIORITY); three.setPriority(Thread.MAX_PRIORITY); one.start( ); two.start( ); three.start( ); } 程序输出结果: three 10 two 5 one 1 注意:该程序的输出结果有可能与上面结果不同。

40 线程同步(Synchronization)
Why is Synchronization(同步) needed? 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题; 线程都是独立的,而且异步执行,也就是说每个线程都包含了运行时所需要的数据或方法,执行时不必关心其它线程的状态或行为。 但是经常有一些同时运行的线程需要共享数据导致访问冲突,例如;一个线程向文件写数据,而同时另一个线程从同一文件中读取数据。 Java制定的线程之间的同步控制机制使多个线程之间能够协调工作,以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。

41 线程同步(Synchronization)
Examples: 自动柜员机: Simultaneous(同时的) operations on your bank account, Can the following operations be done at the same time on the same account? Deposit() Withdraw() 例子:多个线程对一个对象进行操作(程序5)。

42 // 程序5--线程并发引起的不确定性 class SharedObj{ void Play(int n) { System.out.println("运行线程 NO:"+n); try{ Thread.sleep(3); }catch(InterruptedException e) { System.out.println(“线程异常, NO:"+n); } System.out.println("结束线程 NO:"+n);

43 class UserMultThread implements Runnable{
SharedObj UserObj; //共享对象 int num; public UserMultThread(SharedObj o,int n) { UserObj=o; num=n; } public void run( ) { UserObj.Play(num); public class multTheadTwo { public static void main(String args[ ]) { SharedObj Obj=new SharedObj( ); //共享对象 //三个线程共享数据: Obj Thread t1=new Thread( new UserMultThread(Obj, 1) ); Thread t2=new Thread( new UserMultThread(Obj, 2) ); Thread t3=new Thread( new UserMultThread(Obj, 3) ); t1.start( ); t2.start( ); t3.start( ); }

44 程序输出结果: 线程并发引起的不确定性 运行线程 NO:1 运行线程 NO:2 运行线程 NO:3 结束线程 NO:2 结束线程 NO:3
线程执行的顺序不确定!

45 Corrupting Data Problem
由多个线程同时访问并修改的数据对象也称为临界区域(critical regions)。 当多个线程交替访问并修改同一个数据对象时,可能会破坏数据的一致性,或称为污染(corrupt)数据。

46 Corrupting Data Problem
X 100 a=X; b=X; a=a+200; b=b-100; X=a; X=b; 300

47 线程同步 锁定冲突的对象 锁定冲突的方法 加锁机制:每一时刻只能有一个线程对共享资源进行读写,就像上了一把锁,只有拥有钥匙的线程才能访问。
Java通过关键字synchronized实现同步。加锁的方法有两种: 锁定冲突的对象 锁定冲突的方法 当对一个对象或方法使用synchronized修饰,这个对象便被锁定。它访问结束时,让高优先级并处于就绪状态的线程,继续访问被锁定的对象,从而实现资源同步。

48 T1 T2 X 100 a=X; a=a+200; X=a; 300 b=X; b=b-100; X=b; 200
获得(acquire)X上的锁 等待X上的锁 X=a; a=X; a=a+200; 获得X上的锁 释放(release)X上的锁 300 b=X; b=b-100; X=b; synchronized method 释放X上的锁 200

49 线程同步(续) 锁定对象可以出现在任何一个方法中。 例如:修改程序5中的方法run( ) 如下:
锁定冲突的对象,也称为synchronized 语句块 。 语法格式: 冲突的对象 synchronized ( ObjRef ){ // 需要同步执行的语句块 } 锁定对象可以出现在任何一个方法中。 例如:修改程序5中的方法run( ) 如下:

50 class UserMultThread implements Runnable{
SharedObj UserObj; //共享对象 int num; UserMultThread(SharedObj o,int n) { UserObj=o; num=n; } public void run( ) {  //UserObj.Play(num);  synchronized(UserObj) { //锁定共享对象   UserObj.Play(num);  }

51 运行结果如下: 运行线程 NO:1 结束线程 NO:1 运行线程 NO:2 结束线程 NO:2 运行线程 NO:3 结束线程 NO:3
注意: 输出结果有可能不同。 线程同步控制的作用是保证在同一个时刻只能有一个线程可以访问被锁定的对象,即:共享数据。 不能控制线程执行的顺序。

52 线程同步(续) 2. 锁定冲突的方法。语法格式:
synchronized方法的定义 :在可能冲突的方法前面加关键字synchronized。 例如:修改程序5中的方法Play( ) 如下: synchronized void Play(int n) { …… // 中间的程序代码略 } 注意: 1. 对方法run( )无法加锁,不可避免冲突; 2. 对构造函数不能加锁,否则出现语法错误。

53 // 程序5 class SharedObj{ synchronized void Play(int n) { System.out.println("运行线程 NO:"+n); try{ Thread.sleep(3); }catch(InterruptedException e) { System.out.println(“线程异常, NO:"+n); } System.out.println("结束线程 NO:"+n);

54 线程间通信 多线程通信的方法有两种: 1. 把共享变量和方法封装在一个类中实现; 2. 通过wait( )和notify( )方法实现。
public final void wait(long timeout); public final void wait(long timeout, int nanos); public final void wait(); public final void notifyAll(); public final void notify(); Note: Nanosecond 十亿分之一秒, 毫微秒 Timeout 毫秒数

55 java.lang.Object Note: wait() and notify() are methods in class Object: public class java.lang.Object { ... public final void wait() throws InterruptedException; public final void notify(); public final void notifyAll(); }

56 通过封装共享变量实现线程通信 程序6:演示了通过将共享变量和方法封装在一个类中,实现线程通信。 程序6内容:
这个类的对象被多个线程共享。 程序6内容: dataProducer线程和dataConsumer线程共享数据n, dataProducer线程对n产生新的值,而dataConsumer线程读取n的值。

57 //程序6--共享类:共享变量和方法封装在一个类中
class comm{ private int n; //共享变量 private boolean bool=false; //线程切换的条件 void produce(int i) { //冲突方法 while(bool) { } //bool == true, wait n=i; //产生数据 bool=true; //改变条件 System.out.println("\n 产生数据:"+n); } void readout( ) { //冲突方法 while(!bool) { } //bool== false, wait System.out.println(“ 读取数据:”+n);//读取数据 bool=false; //改变条件

58 //程序6-- dataProducer class dataProducer implements Runnable{ comm cm; //共享对象 public dataProducer(comm c) { cm=c; } public void run( ) { //生产者产生5个随机数 for(int i=0;i<5;i++) //通过共享对象cm调用冲突方法产生数据 cm.produce((int)(Math.random( )*100)); } //程序6-- dataConsumer class dataConsumer implements Runnable{ comm cm; //共享对象 dataConsumer(comm c) { cm=c; } public void run( ) { //消费者读取数据 for(int i=0;i<5;i++) //通过共享对象cm调用冲突方法读取数据 cm.readout( ); }

59 //程序6-- 测试 public class multTheadThree { public static void main(String args[ ]) { comm cm=new comm( ); //共享对象 Thread t1=new Thread(new dataProducer(cm)); Thread t2=new Thread(new dataConsumer(cm)); t1.start( ); t2.start( );  } }

60 程序的某次运行结果: 产生数据:81 读取数据:81  产生数据:15 读取数据:15  产生数据:92 读取数据:92  产生数据:98 读取数据:98  产生数据:79 读取数据:79

61 //修改程序6--共享类 class comm{ private int n; private boolean bool=false; void produce(int i) { while(bool) { } //bool == true, wait n=i; bool=true; System.out.println("\n 产生数据:"+n); } void readout( ) { //while(!bool) { } //修改, 不等待。 bool=false; System.out.println(" 读取数据:"+n);

62 //while(!bool) { },dataComsumer 不等待
程序的某次运行结果: 产生数据:26 读取数据:26 产生数据:58

63 通过系统方法实现线程通信 线程同步控制的第二种方法是采用如下几个系统方法: 例如:程序7。
1. wait( )方法:使一个线程进入等待状态,直到被唤醒。 2. notify( )方法:通知等待的线程,该对象的状态已经发生了改变。 3. notifyAll( )方法:唤醒从同一个监视器中用wait( )方法退出的所有线程,使它们按照优先级的顺序重新排队。 Object中的wait和notify的使用方法。二者必须出现在同一个方法内。 例如:程序7。

64 // 程序7 class comm{ private int n; //共享变量 private boolean bool=false; synchronized void produce(int j) { if(bool) { //while(bool == true), wait try{   wait( ); //等待另一个线程的notify()方法唤醒 }catch(InterruptedException e) {   System.out.println("comm 出现异常"); } }else{ n=j; bool=true; System.out.println("\n产生数据: "+n); notify( ); // 唤醒另外一个线程

65 synchronized void readout( ) {
//程序7(续) synchronized void readout( ) { if(!bool) { //while(bool == false), wait try{ wait( ); //等待另一个线程的notify()方法唤醒 }catch(InterruptedException e) { System.out.println(" comm 出现异常"); } }else{ System.out.println("读取数据: "+n); bool=false; notify( ); // 唤醒另一个线程

66 // 程序7 class dataProducer implements Runnable{ comm cm; //共享类对象 dataProducer (comm c) { cm=c; } public void run( ) { try{ for(int i=0;i<5;i++) { cm.produce((int)(Math.random( )*100)); Thread.sleep(10); } }catch(InterruptedException e) { System.out.println("dataProducer 出现异常");

67 // 程序7 class dataConsumer implements Runnable{ comm cm; //共享类对象 dataConsumer(comm c) { cm=c; } public void run( ) { try{ for(int i=0;i<5;i++) { cm.readout( ); Thread.sleep(10); } }catch(InterruptedException e) { System.out.println(" dataConsumer 出现异常");

68 // 程序7 public class multTheadFour{ public static void main(String args[ ]) { comm cm=new comm( ); Thread t1=new Thread(new dataProducer(cm)); Thread t2=new Thread(new dataConsumer(cm)); t1.start( ); t2.start( ); }

69 程序输出结果: 产生数据: 90 读取数据: 90 产生数据: 10 读取数据: 10 产生数据: 65 读取数据: 65 产生数据: 45 读取数据: 45

70 线程调度建议 线程进入等待队列的方式有: 当一个同步方法调用返回时,或一个方法调用了wait( )方法时,另一线程就可访问冲突的对象。
线程a正在使用某对象,线程b调用该对象的同步方法,则b进入等待队列; 调用wait( )方法使线程进入等待队列。 当一个同步方法调用返回时,或一个方法调用了wait( )方法时,另一线程就可访问冲突的对象。 线程调度程序在队列中选取优先级最高的线程。 如果一个线程因调用wait( )而进入队列,则必须调用notify( )才能“解冻”该线程。

71 线程联合(join) join()方法:等待该线程终止。如果不加等待的时间参数,则无限的等待线程运行结束,否则在给定的时间参数后导致线程等待,即丧失线程对象监视器。 一个线程A在占有CPU资源期间,可以让其它线程调用join()和本线程联合, 如: B.join(); 我们称A在运行期间联合了B。 如果线程A在占有CPU资源期间一旦联合B线程,那么A线程将立刻中断执行,一直等到它联合的线程B执行完毕,A线程再重新排队等待CPU资源,以便恢复执行。如果A准备联合的B线程已经结束,那么B.join()不会产生任何效果。

72 线程联合:t线程联合“主线程” public class ThreadTest implements Runnable { public static int a = 0; public void run() { for (int k = 0; k < 5; k++) { a = a + 1; } } public static void main(String[] args) throws Exception{ Runnable r = new ThreadTest(); Thread t = new Thread(r); t.start(); t.join(); //等待t执行完毕,main继续执行 System.out.println(a); } }

73 线程联合 没有t.join()的话,输出:0 或 5都有可能。 有了t.join(),输出:5。 Why?
t.join()会暂停当前线程-main,等t线程执行完, main线程才会继续向下走,所以一定是5.

74 练习 采用多线程编程,模拟出票和售票过程,每产生一张票,就售出一张票。使用多线程之间的同步控制实现。
写一个Tickets类(Tickets.java), 表示所有的票,Tickets类至少有两个域: 票的数量(size) 编号(number)的域 一个线程ticketProducer类,产生票; 一个线程ticketSeller类,卖出票; 一个测试程序测试前面的类。


Download ppt "Java Programming Spring, 2010"

Similar presentations


Ads by Google