- 浏览: 109670 次
文章分类
最新评论
-
luotianwen456123:
文件大小有限制吗
ActiveMQ之三 -- 使用ActiveMQ来传送文件 -
hotbain:
谢谢分享,值得收藏。又学了好多啊!
ActiveMQ之三 -- 使用ActiveMQ来传送文件
Java的每一个对象除了有一个相关的monitor以外(用做synchronized lock),还有一个相关的wait set,用以存放处于WAITING状态的线程
- wait set是线程的集合
- 当Java对象创建的时候,其wait set是空的。对于wait set操作(将线程加入或移出wait set)都是原子操作
- 对于wait set的操作(加入或移出),而且只能通过Object.wait,Object.notify,Object.notifyAll这三个操作来进行。当线程执行到Object.wait指令后,就会进入到wait set集合中;而执行到Object.notify,Object.notifyAll指令后,则通知处于wait set中的线程,条件满足了。
一、背后的理念
- 一个线程需要某个条件继续执行,并且认为别的线程会创造这个条件。于是这个线程就呆在wait set里面等待
- 当别的线程创造了这个条件,则通知等待条件的线程
二、相关的方法
void wait()
|
等待条件发生。
该方法必须在synchronized方法或synchronized块中呼叫 |
void wait(long timeout)
|
等待条件发生。但和wait()方法不同之处在于,如果在timeout(毫秒)的时间内,通知没有到来,则自己略过条件等待,移出wait set,继续执行。
该方法必须在synchronized方法或synchronized块中呼叫 |
void wait(long timeout,int nanos)
|
等待条件发生。观念和wait(long timeout)是一样的。唯一的差别timeout的时间,到了纳秒级别。
该方法必须在synchronized方法或synchronized块中呼叫 |
void notify()
|
通知位于wait set中的某一个线程,条件已经发生了。
该方法必须在synchronized方法或synchronized块中呼叫 |
void notifyAll()
|
通知位于wait set中的所有线程,条件已经发生了。
该方法必须在synchronized方法或synchronized块中呼叫 |
三、生产者和消费者模型的实现
第一种:
public class ProducerConsumerV6 { private List<Integer> list = null; private Random random = null; private Object lock; public ProducerConsumerV6() { list = new ArrayList<Integer>(); random = new Random(); lock = new Object(); } public void produce() throws InterruptedException { synchronized (lock) { if (list.size() == 0) {// 这个对象的wait set里面有consumer线程 lock.notifyAll();// notify() can work } System.out.print(Thread.currentThread().getName() + "\t\t\t" + list + "\t\t\t"); int size = list.size(); for (int i = 0; i < 10 - size; i++) { list.add(random.nextInt(1000)); } System.out.println(list); } } /** * 这里有个问题,当producer产生的食物总量,比consumer的数量少的时候 则有可能发生发生一场状况 * * @throws InterruptedException */ public void consume() throws InterruptedException { synchronized (lock) { while (list.size() == 0) {// 测试竞争条件 // 注意这里必须用while,当一个consumer线程醒来的时候,还必须 // 继续检查list是否为空,如果是则继续等待。否则就继续下一条指 // 令执行 lock.wait(); } System.out.print(Thread.currentThread().getName() + "\t\t\t" + list + "\t\t\t"); list.remove(0); System.out.println(list); } } public static void main(String[] args) throws Exception { ProducerConsumerV6 pc = new ProducerConsumerV6(); for (int i = 0; i < 50; i++) { Thread thread = new Thread(pc.new Consumer()); thread.setName("Consumer " + i); thread.start(); } for (int i = 0; i < 2; i++) { Thread thread = new Thread(pc.new Producer()); thread.setName("Producer " + i); thread.start(); } } public class Producer implements Runnable { @Override public void run() { while (true) { try { produce(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); return; } } } } public class Consumer implements Runnable { @Override public void run() { while (true) { try { consume(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); return; } } } } }
第二种:
public class ProducerConsumerV7 { private List<Integer> list = null; private Random random = null; public ProducerConsumerV7() { list = new ArrayList<Integer>(); random = new Random(); } public synchronized void produce() throws InterruptedException { if (list.size() == 0) {//这个对象的wait set里面有consumer线程 notifyAll();//notify() can work } System.out.print(Thread.currentThread().getName() + "\t\t\t" + list + "\t\t\t"); int size = list.size(); for (int i = 0; i < 10 - size; i++) { list.add(random.nextInt(1000)); } System.out.println(list); } /** * 这里有个问题,当producer产生的食物总量,比consumer的数量少的时候 * 则有可能发生发生一场状况 * @throws InterruptedException */ public synchronized void consume() throws InterruptedException { while(list.size() == 0) {//测试竞争条件 //注意这里必须用while,当一个consumer线程醒来的时候,还必须 //继续检查list是否为空,如果是则继续等待。否则就继续下一条指 //令执行 wait(); } System.out.print(Thread.currentThread().getName() + "\t\t\t" + list + "\t\t\t"); list.remove(0); System.out.println(list); } public static void main(String[] args) throws Exception { ProducerConsumerV7 pc = new ProducerConsumerV7(); for (int i = 0; i < 50; i++) { Thread thread = new Thread(pc.new Consumer()); thread.setName("Consumer " + i); thread.start(); } for (int i = 0; i <2; i++) { Thread thread = new Thread(pc.new Producer()); thread.setName("Producer " + i); thread.start(); } } public class Producer implements Runnable { @Override public void run() { while (true) { try { produce(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); return; } } } } public class Consumer implements Runnable { @Override public void run() { while (true) { try { consume(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); return; } } } } }
四,其他
- Object.wait方法和Thread.sleep方法的不同之处在于,Object.wait方法需要获得对象的synchronized 锁――即对象的Monitor。Object.wait方法执行时,线程就会进入对象的wait set中,synchronized锁就会被自动释放掉(由JVM内部完成这个操作)。一旦接受到通知,线程从Object.wait中返回之前,必须首先获得synchronized锁。所以Java线程Wait-And-Notification机制,必须有赖于synchronized锁。所以上面表格中所列的几个方法必须在synchronized方法或synchronized块中执行。
- 当线程从wait方法中唤醒以后,这时已经获取了synchronized锁,就会接着wait指令后面的指令继续执行。
- notify() 和 notifyAll()方法类似,区别在于notifyAll会“唤醒”处于wait set中的所有的线程,只是这些线程仍需竞争synchronized lock。只有获取了synchronized lock的线程才能继续执行。(似乎这些线程的状态发生了迁移,从WAITING态迁移到了BLOCKED状态),而notify只是唤醒一个线程,但具体是哪个线程由JVM决定,我们自己对此无能为力。
参考:
- http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.2
- 《Java Threads 3rd Edtion》
发表评论
-
java线程:jdk 7中的Fork/Join模式
2012-03-30 00:12 2164//尚未研究完成... package org. ... -
java线程:synchronized
2012-03-29 17:22 1071Java线程提供了很多的线程通讯机制,最为基础就是synchr ... -
java线程:Atomic(原子的)
2012-03-29 01:54 25004一、何谓Atomic? Atomic一词跟原子 ... -
Java线程:什么是线程
2012-03-28 22:03 3633一、什么是线程 线程是指令的执行路径。在Java语言中, ... -
ClassLoader
2012-03-19 11:36 0http://onjava.com/lpt/a/5586 -
JVM系列:-Xss调整Stack Space的大小
2011-10-26 01:06 5271Java程序中,每个线程都有自己的Stack Space。这个 ... -
Xml And JavaBean
2011-10-25 19:46 1118一、通过Jaxb来做二者之间的转换 1. 使用jaxb的工具 ...
相关推荐
NGUI is a very powerful UI system and event notification framework. Features: -Full Inspector integration -No need to hit Play to see the results -What you see in the Scene view is what you get in ...
- Improvement: TGMGeoCode -> overrided Notification method to control Marker property - Improvement: TGMGeoCode -> xxToStr and StrToxxx moved to the TTransform class into the GMFunctions unit - ...
NGUI is a very powerful UI system and event notification framework. Features - Editor integration, WYSIWYG - Localization, data binding, delegates, events - Supports all platforms - Make UIs that ...
React Native Local and Remote Notifications for iOS and Android Supported React Native Versions Component Version RN Versions README 1.0.7 = 2.1.0 >= 0.33 Installation npm install --save ...
Laravel开发-laravel-push-notification Push Notification 服务端支持 app的推送通知发送工具,支持结果的apns和安装的gcm
NULL 博文链接:https://kakukemeit.iteye.com/blog/1806388
资源来自pypi官网。 资源全名:cdk-codepipeline-badge-notification-2.0.20.tar.gz
react-native-in-app-notification-master.rar
资源分类:Python库 所属语言:Python 资源全名:cdk-codepipeline-badge-notification-0.2.37.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
JEDEC J-STD-048:2014 Notification Standard for Product Discontinuance - 完整英文电子版(8页).zip
JEDEC J-STD-048:2014 Notification Standard for Product Discontinuance - 完整英文电子版(8页).pdf
极光推送 JAVA服务端 jpush-client-3.2.8 与 集成源码 jpush-api-java-client-master
Android入门开发实例--Toast、Notification、Intent应用
资源分类:Python库 所属语言:Python 资源全名:sentry-dingtalk-notification-1.0.5.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
Android 源码:toast_and_notification,100ms延迟后,振动250ms,停止100ms后振动500ms,没有搞懂具体是干什么用的,本人非专业人士,发在源码爱好者,供喜欢的人研究。
当与某人共享屏幕时,移除Google Hangout窗口顶部的丑陋绿色通知栏。 您仍然可以通过单击环聊窗口左侧面板中的屏幕共享图标来选择停止共享。注意:如果在屏幕底部出现黑条,只需在任何方向上重新调整一次窗口大小...
Jenkins插件:在企业微信通知插件的基础上,添加了失败原因以及失败日志做为消息的一部分进行发送。
oracle:Heap size 3597K exceeds notification threshold 解决方法
NGUI is a very powerful UI system and event notification framework. Features - Editor integration, WYSIWYG - Localization, data binding, delegates, events - Supports all platforms - Make UIs that...
Laravel开发-laravel-push-notification 向移动设备(APN、GCM、WPN、BlackBerry)发送推送通知的Laravel包