JAVA 并发编程-传统线程同步通信技术(四)
2015-07-22 11:03
471 查看
首先介绍几个概念:
这些方法都是Object的方法,并不是线程的方法!wait()方法
wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。 当前的线程必须拥有当前对象的monitor,也即lock,就是锁。 线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。 要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。 与sleep比较: 当线程调用了wait()方法时,它会释放掉对象的锁。 另一个会导致线程暂停的方法:Thread.sleep(),它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。notify()方法
notify()方法会唤醒一个等待当前对象的锁的线程。 如果多个线程在等待,它们中的一个将会选择被唤醒。这种选择是随意的,和具体实现有关。(线程等待一个对象的锁是由于调用了wait方法中的一个)。 被唤醒的线程是不能被执行的,需要等到当前线程放弃这个对象的锁。 被唤醒的线程将和其他线程以通常的方式进行竞争,来获得对象的锁。也就是说,被唤醒的线程并没有什么优先权,也没有什么劣势,对象的下一个线程还是需要通过一般性的竞争。 notify()方法应该是被拥有对象的锁的线程所调用。 换句话说,和wait()方法一样,notify方法调用必须放在synchronized方法或synchronized块中。 wait()和notify()方法要求在调用时线程已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或synchronized块中。线程同步通信实现demo:
传统线程同步通信技术,子线程循环10次,接着主线程循环100次,又回到子线程循环10次,接着再回到主线程又循环100次,如此循环50次public class TraditionalThreadCommunication {
/**
* @param args
*/
public static void main(String[] args) {
final Business business = new Business();
//创建了一个线程,并启动
new Thread(
new Runnable() {
@Override
public void run() {
for(int i=1;i<=50;i++){
//business的子函数
business.sub(i);
}
}
}
).start();
//因为mian方法本身就占用一个线程,所以主线程不需要再new Thread
for(int i=1;i<=50;i++){
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;
//互斥对象为business,即在同一时刻只能访问sub或main其中一个方法
public synchronized void sub(int i){
//当bShouldSub==false时等待
while(!bShouldSub){
try {
//方法使当前线程主动释放互斥锁,并进入该互斥锁的等待队列。(也就是说,它使当前线程暂停执行,
//等待其他线程执行notify()方法或者notifyall()方法后再继续执行本线程。)
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
//this代表什么?--代表Business
//唤醒下一个线程
//唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。
//选择是任意性的,并在对实现做出决定时发生。
this.notify();
}
public synchronized void main(int i){
//当bShouldSub==true时等待
while(bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
this.notify();
}
}
打印结果:
总结:
wait()和notify()方法要求在调用时线程已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或synchronized块中。synchronized保证了main和sub两个方法在同一时刻只能有一个在执行,那么bShouldSub值就是在判断该哪个方法执行。 执行过程可能为:sub()方法先执行(当然也可能是main方法先执行,只是bShouldSub==true,则会的wait),bShouldSub==true,执行for循环,之后设置bShouldSub=false,并唤醒等待线程,这时可能还是执行sub()方法(被唤醒的线程并没有什么优先权,也没有什么劣势,对象的下一个线程还是需要通过一般性的竞争),但此时bShouldSub==false,故执行while语句,wait,然后main()方法执行。相关文章推荐
- MyEclipse安装插件的几种方式(适用于Eclipse或MyEclipse其他版本)
- ubuntu jdk环境配置
- spring+websocket综合(springMVC+spring+MyBatis这是SSM框架和websocket集成技术)
- Java中的static关键字解析
- 【Java】编写一个方法,对字符串数组进行排序,将所有变位词排在相邻的位置
- Java开发常用工具类
- Spring AOP实例
- Java图形用户界面布局控制Layout练习
- java常用语句
- java最简单实现LRUCache
- Spring笔记
- 【Java】两个排序后的数组A和B,其中A的末端有足够的缓冲容纳B。编写一个方法,将B合并入A并排序。
- myEclipse2015启动myEclipse时发现了以元素"d:disk"的无效内容
- JAVA之BigInteger
- JAVA Calendar详解
- Java Web乱码分析及解决方案(三)——响应乱码
- Eclipse ADT启动报“fail to load the jni shared library”问题解决方案
- Java 应用
- 如何在一台新电脑上配置JAVA开发环境
- Java对象的序列化和反序列化