2.5 join() 使调用join()的线程执行完毕后才能执行其它线程,在一定意义上,它可以实现同步的功能。 例16: class TestThreadMethod extends Thread{ public static int shareVar = 0; public TestThreadMethod(String name){ super(name); } public void run(){ for(int i=0; i<4; i++){ System.out.println(" " + i); try{ Thread.sleep(3000); } catch(InterruptedException e){ System.out.println("Interrupted"); } } } } public class TestThread{ public static void main(String[] args){ TestThreadMethod t1 = new TestThreadMethod("t1"); t1.start(); try{ t1.join(); } catch(InterruptedException e){} t1.start(); } } 运行结果为: 0 1 2 3 0 1 2 3
3. class Object下常用的线程函数 wait()、notify()和notifyAll()这三个函数由java.lang.Object类提供,用于协调多个线程对共享数据的存取。 3.1 wait()、notify()和notifyAll() 1) wait()函数有两种形式:第一种形式接受一个毫秒值,用于在指定时间长度内暂停线程,使线程进入停滞状态。第二种形式为不带参数,代表waite()在notify()或notifyAll()之前会持续停滞。 2) 当对一个对象执行notify()时,会从线程等待池中移走该任意一个线程,并把它放到锁标志等待池中;当对一个对象执行notifyAll()时,会从线程等待池中移走所有该对象的所有线程,并把它们放到锁标志等待池中。 3) 当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。 例17: 下面,我们将对例11中的例子进行修改 class TestThreadMethod extends Thread{ public static int shareVar = 0; public TestThreadMethod(String name){ super(name); } public synchronized void run(){ if(shareVar==0){ for(int i=0; i<10; i++){ shareVar++; if(shareVar==5){ try{ this.wait(); //(4) } catch(InterruptedException e){} } } } if(shareVar!=0){ System.out.print(Thread.currentThread().getName()); System.out.println(" shareVar = " + shareVar); this.notify(); //(5) } } } public class TestThread{ public static void main(String[] args){ TestThreadMethod t1 = new TestThreadMethod("t1"); TestThreadMethod t2 = new TestThreadMethod("t2"); t1.start(); //(1) //t1.start(); (2) t2.start(); //(3) } } 运行结果为: t2 shareVar = 5 因为t1和t2是两个不同对象,所以线程t2调用代码(5)不能唤起线程t1。如果去掉代码(2)的注释,并注释掉代码(3),结果为: t1 shareVar = 5 t1 shareVar = 10 这是因为,当代码(1)的线程执行到代码(4)时,它进入停滞状态,并释放对象的锁状态。接着,代码(2)的线程执行run(),由于此时shareVar值为5,所以执行打印语句并调用代码(5)使代码(1)的线程进入可执行状态,然后代码(2)的线程结束。当代码(1)的线程重新执行后,它接着执行for()循环一直到shareVar=10,然后打印shareVar。 3.2 wait()、notify()和synchronized waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。 例18: class TestThreadMethod extends Thread{ public int shareVar = 0; public TestThreadMethod(String name){ super(name); new Notifier(this); } public synchronized void run(){ if(shareVar==0){ for(int i=0; i<5; i++){ shareVar++; System.out.println("i = " + shareVar); try{ System.out.println("wait......"); this.wait(); } catch(InterruptedException e){} } } } } class Notifier extends Thread{ private TestThreadMethod ttm; Notifier(TestThreadMethod t){ ttm = t; start(); } public void run(){ while(true){ try{ sleep(2000); } catch(InterruptedException e){} /*1 要同步的不是当前对象的做法 */ synchronized(ttm){ System.out.println("notify......"); ttm.notify(); } } } } public class TestThread{ public static void main(String[] args){ TestThreadMethod t1 = new TestThreadMethod("t1"); t1.start(); } } 运行结果为: i = 1 wait...... notify...... i = 2 wait...... notify...... i = 3 wait...... notify...... i = 4 wait...... notify...... i = 5 wait...... notify...... 4. wait()、notify()、notifyAll()和suspend()、resume()、sleep()的讨论 4.1 这两组函数的区别 1) wait()使当前线程进入停滞状态时,还会释放当前线程所占有的“锁标志”,从而使线程对象中的synchronized资源可被对象中别的线程使用;而suspend()和sleep()使当前线程进入停滞状态时不会释放当前线程所占有的“锁标志”。 2) 前一组函数必须在synchronized函数或synchronized block中调用,否则在运行时会产生错误;而后一组函数可以non-synchronized函数和synchronized block中调用。 4.2 这两组函数的取舍 Java2已不建议使用后一组函数。因为在调用wait()时不会释放当前线程所取得的“锁标志”,这样很容易造成“死锁”。
<<上一页
1
2
3
|