博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
学习笔记 java多线程(四)线程间协作
阅读量:5086 次
发布时间:2019-06-13

本文共 3177 字,大约阅读时间需要 10 分钟。

 

                通过保证在临界区上多个线程的相互排斥,线程间可以完全避免竞争状态的发生,但是有时候还是需要线程之间的相互协作。使用条件(Condition)便于线程间通信。一个线程可以指定在某种条件下该做什么。标间是通过调用Lock对象的newCoditionn()方法来实现线程之间的相互通信的。

          

          一旦创建一个条件,就可使用await()、signal()、signalAll()方法来实现线程间通信。await()方法可以让当前线程都处于等待状态,知道条件放生。signal()方法唤醒一个等待的线程,而signalAll()方法唤醒所有等待线程。

         假设创建并启动两个任务,一个用来向账户存款,另一个从同一个账户取款。当取款数额大于账户余额的时,取款线程必须等待。不管什么时候,只要向账户新存了一笔资金,存款线程必须通知提款线程重新尝试。如果余额仍为达到取款数额、提款线程必须继续等待新的存款。

       为了同步这些操作,使用一个由条件的锁newDeposit(即增加到账户的新存款)。如果余额小于取款数额,提款任务将等待newDeposit条件。当存款任务给账户增加资金时,存款任务唤醒等待中的提款任务在次尝试。

                   

看下面的例子

 

package LianXi;import java.util.concurrent.*;  import java.util.concurrent.locks.*;  public class ThreadCooperation{     private static Account _account = new Account();      public static void main(String[] args) {          ExecutorService executor = Executors.newCachedThreadPool();  	    executor.execute(new WithdraoTask()); 		executor.execute(new AddMoneyTask());      }           //执行任务想账户中加钱      public static class AddMoneyTask implements Runnable{          @Override          public void run(){  			while(true){                _account.deposit((int)(Math.random()*1000));  			}        }      }          //取款任务   public static class  WithdraoTask implements Runnable{	   @Override		  public void run(){		    while(true){				_account.withDraw((int)(Math.random()*5000));			}	   }   }   //账户      public static class  Account{          private static Lock _lock = new ReentrantLock(true); //创建一个锁  	 	private static Condition newDeposit = _lock.newCondition(); // 创建一个条件         private int _moneyCount=0;           public int getMoneyCount(){              return _moneyCount;        }          public void deposit(int amount){             _lock.lock(); //获得锁             int newMoneyCount = getMoneyCount()+amount;            try{                               _moneyCount=newMoneyCount;                 System.out.println("\n新存入了$"+amount+_account.getAccountInfor());  			   newDeposit.signalAll();			    Thread.sleep(1000);            } catch(InterruptedException ex) {                          } finally {                  _lock.unlock();             }                      }  	   public void withDraw(int amount){			_lock.lock();			try{				while(getMoneyCount()
运行结果:

 

-

    

    需要注意的地方:1、在取款任务中使用Wile判断,避免永久等待。因为当存款任务调用signalAll()的时候while条件依然为true 。如要再次判断余额和要取的数额,以确定是否可以取款。

                                   2、一旦线程调用雕件的await()方法,进会进入等待状态,如果忘记调用signal 或者signalAll() 就回进入永久等待状态。

                                  3、条件由Lock对象创建,为了嗲用任务方法(如:await。signal 、signalAll),必须首先获得锁。,如果没有获得锁,就调用这些方法会排除 IIlegalMonitorStateException异常。

       锁和条件java5 引入的内容,在java 5 之前,线程通信是使用对象的内容见识起编程实现的。锁和条件与内置监视器相比是非常强大而且灵活的。

     监视器(monitor)是一个相互作用切具备同步能力的对象,监视器中的一个时间点上,只能有一个线程执行一个方法。线程通过获取监视器上的锁进入监视器,并且通过在方法或块块上使用synchronized关键字来实现。在执行同步方法或块之前,线程必须获取锁。如果条件不适合线程在监视器内继续执行,线程可能在监视器中等待。可以对监视器对象调用wait()方法来释放锁,这样其它的一些监视器中的线程就可以获取它,也就有可能改变监视器的状态。当条件合适时,另一个线程可以调用notiry()或者notifyAll()房东发来说通知一个或多有的等待线程重新获取锁,并且恢复执行。

    wait()、notify()、notifyAll*()方法必须在这些方法的接收对象的同步方法或同步块中调用,否则,就回出现IIlegalMonitorStateException异常。

可以将上面的程序修改成为moniitor版本。

       当调用wait()方法时,它中止线程的同事释放对象的锁,当线程被通知之后重新启动时,锁就被重新自动获取。对象上的wait()、nitify()、notifyAll方法类似于状态撒谎能够的 await()、signal()和aignalAll()方法。

     题外话。PowerDesigner 、画图工具、qq截屏还真是不错,配合使用 大笑,越来越上手了。

  

 

 

 

转载于:https://www.cnblogs.com/duanjie/archive/2012/04/26/2489175.html

你可能感兴趣的文章
ios类、分类、扩展类 你一定要懂
查看>>
加密解密字符串
查看>>
编程之美读书笔记之---”不要被阶乘吓到“
查看>>
Windbg 的使用和常用命令
查看>>
GC之九--gc调优
查看>>
Python求解啤酒问题(携程2016笔试题)
查看>>
shc加密shell脚本
查看>>
int _tmain(int argc, _TCHAR* argv[])
查看>>
Linux设备驱动(转)
查看>>
聊天室和弹幕的js实现感觉没差
查看>>
flipsnap.js 源码阅读备份
查看>>
Ubuntu11.10 源码编译安装PHP5.3.8 [转]
查看>>
2-sat专题
查看>>
jquery实现智能表单
查看>>
Android学习经验分享
查看>>
C语言的本质(36)——makefile基础
查看>>
python2 升级 3
查看>>
第二本书 (课后题)懒得写了 准备都写这一个里面了- -、
查看>>
database
查看>>
数据库编程技术总结
查看>>