Java 同步方式 (2) —— wait和notify/notifyall
2012-06-23 05:09
519 查看
Java 中除了关键字 synchronized 能够实现线程同步外,还可以使用 wait 和 notify/notify 实现同步。
wait 方法是使拥有当前对象(object)的线程(thread)放弃锁(release lock),进入睡眠状态
notify 通知该对象(object)因上面调用wait而等待的某一进程重新唤醒启动
notifyAll 通知在对象(object)上因调用wait而等待的所有进程启动,这些进程根据优先级顺序执行
一个线程在其生命周期内总是处于某种状态:
创建: 当一个线程对象被声明并创建后,它处于“创建”状态;
就绪:线程对象调用 start() 方法后,将进入“就绪”状态,处于“就绪”状态的线程不是立即执行,而是进入就绪队列,等待CPU;
运行:当就绪队列中具有最高优先级的就绪线程被调度并获得CPU时,便进入“运行”状态,执行 run() 方法,run 方法中定义了线程的操作和功能;
非运行:处于“运行”状态的线程可能因为某些原因 (例如人为挂起)进入“非运行”状态,让出CPU并临时中止自己的执行;
停止:线程完成了它的全部工作或调用 stop() 方法强制中止线程,线程就进入“停止”状态。
wait 与 sleep 区别
wait - sleep 示例(区别)
thread is starting...
Waiting for th to complete...
Thread is running...
i = 0; total = 0
i = 1; total = 1
i = 2; total = 3
i = 3; total = 6
i = 4; total = 10
i = 5; total = 15
i = 5 sleep(3000)
i = 6; total = 21
i = 7; total = 28
i = 8; total = 36
i = 9; total = 45
Total is : 45
================================
wait - notify 示例(生产者 - 消费者)
Put n : 0
Get n : 0
Put n : 1
Get n : 1
Put n : 2
Get n : 2
Put n : 3
Get n : 3
Put n : 4
Get n : 4
首先两个线程启动,他们的执行占用CPU多少随机,但是这里因为加了一个锁的Boolean型变量,而控制了put与set.
首先:创建了一个对象Q,创建了一个Producer,一个Consumer,这两个对象在构造方法中启动了线程.
第一步:
对于Producer来说,会首先去调用put方法,因为valueSet是默认值是false,所以在Q的put方法不执行wait 而是执行 this.n = n 赋值操作,执行完毕后设置为valueSet = true
对于Consumer来说,会首先去调用get方法,因为valueSet是默认值是false,所以该线程会执行wait(等待valueSet 赋值状态为true)
第二步:
对于Producer来说,因为valueSet已经变成true,所以会wat.
对于Consumer来说,因为valueSet已经变成true,所以会执行下面的code(get value),然后设置valueSet为false.
第三步:
Producer执行put方法,因为valueSet为false
Consumer等待(重复第一步)
依次类推,方法执行...
这里关键是加了一个共享的变量 valueSet 来判是该取值get,还是put值。当然有了wait跟notify才使它成为了可以实现的。
但是不管怎样,wait是使目前控制该对象(Q的对象q)的线程wait(等待),notify是使前面在该对象上面wait的方法继续执行.
示例代码下载
wait 方法是使拥有当前对象(object)的线程(thread)放弃锁(release lock),进入睡眠状态
notify 通知该对象(object)因上面调用wait而等待的某一进程重新唤醒启动
notifyAll 通知在对象(object)上因调用wait而等待的所有进程启动,这些进程根据优先级顺序执行
一个线程在其生命周期内总是处于某种状态:
创建: 当一个线程对象被声明并创建后,它处于“创建”状态;
就绪:线程对象调用 start() 方法后,将进入“就绪”状态,处于“就绪”状态的线程不是立即执行,而是进入就绪队列,等待CPU;
运行:当就绪队列中具有最高优先级的就绪线程被调度并获得CPU时,便进入“运行”状态,执行 run() 方法,run 方法中定义了线程的操作和功能;
非运行:处于“运行”状态的线程可能因为某些原因 (例如人为挂起)进入“非运行”状态,让出CPU并临时中止自己的执行;
停止:线程完成了它的全部工作或调用 stop() 方法强制中止线程,线程就进入“停止”状态。
wait 与 sleep 区别
wait | sleep | |
归属类 | 属于Object类(java.lang.Object) | 属于Thread类(java.lang.Thread),静态方法 |
释放锁 | 释放了锁,其它线程同步块或方法 | 没有释放锁,不出让系统资源(如cpu) |
中断唤醒 | wait一般不会加时间限制,而是判断是否满足符合条件; 如果符合条件,则notify/notifyall唤醒 | sleep(milliseconds)后自动唤醒, 如果时间不到可用interrupt()强制中断 |
适用范围 | 同步方法或同步块使用(synchronized) | 任何地方都可使用(main、thread线程) |
捕获异常 | 必须捕获异常(try/catch) | 不需要捕获异常 |
package com.homer.thread; public class waitsleep { public static void main(String[] args) { ThreadDemo th = new ThreadDemo(); th.start(); System.out.println("thread is starting..."); synchronized (th) { try { System.out.println("Waiting for th to complete..."); // th.wait(1000); // 等待1秒后,立刻执行 th.wait(); // 线程等待,notify唤醒后执行 } catch (Exception e) { e.printStackTrace(); } System.out.println("Total is : " + th.total); // 线程唤醒后,执行 } } } class ThreadDemo extends Thread { int total; @Override public void run(){ try { Thread.sleep(2000); // 睡眠2秒 synchronized(this){ System.out.println("Thread is running..."); for(int i=0; i<10; i++) { total += i; System.out.println("i = " + i + "; total = " + total); if(i==5) { System.out.println("i = 5 sleep(3000)"); Thread.sleep(3000); // i = 5时,睡眠3秒 } } this.notify(); } } catch (Exception e) { e.printStackTrace(); } } }运行结果:
thread is starting...
Waiting for th to complete...
Thread is running...
i = 0; total = 0
i = 1; total = 1
i = 2; total = 3
i = 3; total = 6
i = 4; total = 10
i = 5; total = 15
i = 5 sleep(3000)
i = 6; total = 21
i = 7; total = 28
i = 8; total = 36
i = 9; total = 45
Total is : 45
================================
wait - notify 示例(生产者 - 消费者)
package com.homer.thread; public class waitnotify { public static void main(String[] args) { Q q = new Q(); new Producer(q); new Consumer(q); } } class Producer implements Runnable { Q q = null; public Producer(Q q) { this.q = q; (new Thread(this, "Producer")).start(); } @Override public void run() { int i = 0; while(i<5) { q.put(i++); } } } class Consumer implements Runnable { Q q = null; public Consumer(Q q) { this.q = q; (new Thread(this, "Consumer")).start(); } @Override public void run() { while(q.get()<5){ } } } class Q { int n; boolean valueSet = false; public synchronized int get() { if(!valueSet) { // if valueSet == false,wait else try to got value try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Get n : " + n); valueSet = false; notify(); return n; } public synchronized void put(int n) { if(valueSet) { // if valueSet == true,already have value so wait fetch,else put try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.n = n; System.out.println("Put n : " + n); valueSet = true; notify(); } }运行结果:
Put n : 0
Get n : 0
Put n : 1
Get n : 1
Put n : 2
Get n : 2
Put n : 3
Get n : 3
Put n : 4
Get n : 4
首先两个线程启动,他们的执行占用CPU多少随机,但是这里因为加了一个锁的Boolean型变量,而控制了put与set.
首先:创建了一个对象Q,创建了一个Producer,一个Consumer,这两个对象在构造方法中启动了线程.
第一步:
对于Producer来说,会首先去调用put方法,因为valueSet是默认值是false,所以在Q的put方法不执行wait 而是执行 this.n = n 赋值操作,执行完毕后设置为valueSet = true
对于Consumer来说,会首先去调用get方法,因为valueSet是默认值是false,所以该线程会执行wait(等待valueSet 赋值状态为true)
第二步:
对于Producer来说,因为valueSet已经变成true,所以会wat.
对于Consumer来说,因为valueSet已经变成true,所以会执行下面的code(get value),然后设置valueSet为false.
第三步:
Producer执行put方法,因为valueSet为false
Consumer等待(重复第一步)
依次类推,方法执行...
这里关键是加了一个共享的变量 valueSet 来判是该取值get,还是put值。当然有了wait跟notify才使它成为了可以实现的。
但是不管怎样,wait是使目前控制该对象(Q的对象q)的线程wait(等待),notify是使前面在该对象上面wait的方法继续执行.
示例代码下载
相关文章推荐
- Java 同步方式 (2) —— wait和notify/notifyall
- Java 同步方式 (2) —— wait和notify/notifyall
- Java 同步方式 (1) —— synchronized 和 Java 同步方式 (2) —— wait和notify/notifyall (很全面)
- Java 同步方式 (2) —— wait和notify/notifyall
- Java 同步方式 (2) —— wait和notify/notifyall
- Java多线程---------同步与死锁:synchronized;等待与唤醒:wait、notify、notifyAll;生命周期
- Java多线程--同步与死锁:synchronized;等待与唤醒:wait、notify、notifyAll;生命周期
- java并发包中的Condition和Lock 取代Synchronized、wait、notify/notifyAll实现线程的同步与互斥
- JAVA 的wait(), notify()与synchronized同步机制
- JAVA线程同步 (一)wait(), notify()和notifyAll()使用
- java线程同步原理及wait,notify的用法及与sleep的区别
- 转:【Java并发编程】之十:使用wait/notify/notifyAll实现线程间通信的几点重要说明
- Java同步机制:synchronized,wait,notify
- 理解 JAVA线程同步及其中中wait()和notify()简洁例子
- Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
- Java可阻塞队列的两种实现方式 (传统wait/notify和jdk1.5以后的lock)
- java线程总结2--wait/notify(all)/sleep以及中断概念
- Java多线程wait,notify以及同步锁的运用实例
- Java - Why wait notify and notifyAll called from synchronized block or method in Java
- java wait notify notifyall