thread的wait\notify实现线程通信
2016-04-08 10:33
573 查看
背景:
之前的文章介绍过wait与sleep的区别,本文从另一个角度梳理一种实现线程通信的方式。
正文:
wait()、notify()和notifyAll()是Object类中的方法:
1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)
3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;
为何这三个不是Thread类声明中的方法,而是Object类中声明的方法(当然由于Thread类继承了Object类,所以Thread也可以调用者三个方法)?其实这个问题很简单,由于每个对象都拥有monitor(即锁),所以让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。而不是用当前线程来操作,因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。
运行结果如下:
当然wait还有几个重载的方法设置超时时间:
public final void wait(long timeout, int nanos) throws InterruptedException
导致线程进入等待状态直到它被通知或者经过指定的时间.
线面来看个常用的生产者消费者模式。模拟一个容器:
运行结果如下:
1. 线程的等待或者唤醒,并不是让线程调用自己的wait或者notify方法,而是通过调用线程共享对象的wait或者notify方法来实现。
2. 线程要调用某个对象的wait或者notify方法,必须先取得该对象的监视器。
3. 线程的协作必须以线程的互斥为前提,这种协作实际上是一种互斥下的协作。
好了,本篇先到这里,下篇改用condition实现。
参考:
http://www.cnblogs.com/dolphin0520/p/3920385.html
之前的文章介绍过wait与sleep的区别,本文从另一个角度梳理一种实现线程通信的方式。
正文:
wait()、notify()和notifyAll()是Object类中的方法:
1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)
3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;
为何这三个不是Thread类声明中的方法,而是Object类中声明的方法(当然由于Thread类继承了Object类,所以Thread也可以调用者三个方法)?其实这个问题很简单,由于每个对象都拥有monitor(即锁),所以让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。而不是用当前线程来操作,因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。
package thread; public class NotifyTest { public static Object object = new Object(); public static void main(String[] args) { Thread1 thread1 = new Thread1(); Thread2 thread2 = new Thread2(); thread1.start(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } thread2.start(); } static class Thread1 extends Thread{ @Override public void run() { synchronized (object) { try { object.wait(); } catch (InterruptedException e) { } System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁"); } } } static class Thread2 extends Thread{ @Override public void run() { synchronized (object) { object.notify(); System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()");
<pre name="code" class="java"> <span style="white-space:pre"> </span>System.out.println("线程"+Thread.currentThread().getName()+"释放了锁");} } }}
运行结果如下:
当然wait还有几个重载的方法设置超时时间:
public final void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException
导致线程进入等待状态直到它被通知或者经过指定的时间.
线面来看个常用的生产者消费者模式。模拟一个容器:
package thread; import java.util.LinkedList; public class Depository { int capability = 5; private static LinkedList<Product> pool = new LinkedList(); public LinkedList getPool() { return pool; } public synchronized int getSize() { return pool.size(); } public synchronized boolean isEmpty() { return pool.isEmpty(); } public synchronized boolean isFull() { if (this.getSize() == this.capability) { return true; } else { return false; } } public synchronized void addLast(Product p) { this.notifyAll(); if (!this.isFull()) { pool.addFirst(p); //System.out.println("当前线程的名称:" + Thread.currentThread().getName()); System.out.println(Thread.currentThread().getName() + " 放入一个产品"); System.out.println("仓库已经有 " + this.getSize() + " 个了"); } else { System.out.println("仓库满了,该线程" + Thread.currentThread().getName() + "等待"); try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public synchronized Product remove(){ if(!this.isEmpty()){//不为空,取出 this.notifyAll(); // Product p= pool.removeFirst(); return p; }else{//等待 System.out.println("仓库空了,该线程" + Thread.currentThread().getName() + "等待"); try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } } }
package thread; public class Product { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString(){ return "product:"+this.name; } }
package thread; /** * * @author zhangliang * * 2016年4月8日 下午1:57:32 */ public class PCTest { public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub PCTest test = new PCTest(); Depository pool = new Depository(); Producer pro=test.new Producer(pool); Consumer con=test.new Consumer(pool); Thread p = new Thread(pro); Thread c1 = new Thread(con); Thread c2 = new Thread(con); p.start(); c1.start(); c2.start(); Thread.sleep(500); p.interrupt(); c1.interrupt(); c2.interrupt(); } class Consumer implements Runnable{ //消费者线程拥有的资源 private Depository pool=null; //构造函数 public Consumer(Depository pool) { this.pool=pool; } volatile boolean flag=true; @Override public void run() { while(flag){ try { Thread.sleep(100); } catch (InterruptedException e) { flag =false; } Product p = this.pool.remove(); if(p!= null) { System.out.println("线程"+Thread.currentThread().getName()+"消费了"+p.toString()); } } } } //生产者线程 class Producer implements Runnable{ //生产者线程拥有的资源 private Depository pool=null; //构造函数 public Producer(Depository pool) { this.pool=pool; } @Override public void run() { boolean flag=false; while(true) { if(!pool.isFull()) { Product p = new Product(); p.setName("p:"+System.currentTimeMillis()); this.pool.addLast(p); try { Thread.sleep(10); } catch (InterruptedException e) { flag =false; } } } } } }
运行结果如下:
Thread-0 放入一个产品 仓库已经有 1 个了 Thread-0 放入一个产品 仓库已经有 2 个了 Thread-0 放入一个产品 仓库已经有 3 个了 Thread-0 放入一个产品 仓库已经有 4 个了 Thread-0 放入一个产品 仓库已经有 5 个了 线程Thread-2消费了product:p:1460095150363 Thread-0 放入一个产品 仓库已经有 4 个了 线程Thread-1消费了product:p:1460095150373 Thread-0 放入一个产品 仓库已经有 5 个了 Thread-0 放入一个产品 仓库已经有 5 个了 线程Thread-2消费了product:p:1460095150443 线程Thread-1消费了product:p:1460095150536 Thread-0 放入一个产品 仓库已经有 5 个了 线程Thread-2消费了product:p:1460095150546 Thread-0 放入一个产品 线程Thread-1消费了product:p:1460095150433 仓库已经有 4 个了 Thread-0 放入一个产品 仓库已经有 5 个了 线程Thread-1消费了product:p:1460095150646 Thread-0 放入一个产品 仓库已经有 5 个了 线程Thread-2消费了product:p:1460095150739 Thread-0 放入一个产品 仓库已经有 5 个了 线程Thread-2消费了product:p:1460095150749 线程Thread-1消费了product:p:1460095150636 Thread-0 放入一个产品 仓库已经有 4 个了 Thread-0 放入一个产品 仓库已经有 5 个了
1. 线程的等待或者唤醒,并不是让线程调用自己的wait或者notify方法,而是通过调用线程共享对象的wait或者notify方法来实现。
2. 线程要调用某个对象的wait或者notify方法,必须先取得该对象的监视器。
3. 线程的协作必须以线程的互斥为前提,这种协作实际上是一种互斥下的协作。
好了,本篇先到这里,下篇改用condition实现。
参考:
http://www.cnblogs.com/dolphin0520/p/3920385.html
相关文章推荐
- 【原创】k8s源码分析-----kubelet(3)ContainerGC
- [poj 1691] Painting A Board dfs+拓扑排序
- synchronized ,notify(),wait(),Thread.sleep();
- HDOJ 1302(UVa 573) The Snail(蜗牛爬井)
- HDOJ 1302(UVa 573) The Snail(蜗牛爬井)
- 【UVa】11456 - Trainsorting
- 朴素贝叶斯(Naive-Bayes)介绍
- error: linker command failed with exit code 1 (use -v to see invocation)
- Team:Syclover Author:L3m0n Email:iamstudy@126.com
- IBM服务器 RAID5 阵列卡配置教程
- 算法之动态规划-矩阵链相乘(matrix-chain multiplication)
- HP服务器RAID 0阵列配置教程
- POJ-3411 Paid Roads
- 11. Container With Most Water
- HDOJ 1023 Train Problem II(卡特兰数+大数乘除法)
- 解决gradle project sync failed.Basic functionality(e.g.editing,debugging) will not work properly
- hdu 1839 Delay Constrained Maximum Capacity Path 二分下限+最短路spfa
- 【POJ 1765】 November Rain(离散化+扫描线)
- Hdu4952 - Number Transformation - 数论(2014 Multi-University Training Contest 8)
- [HDU 5029] Relief grain (树链剖分+线段树)