JAVA 多线程通信 详解与举例
来源:互联网 发布:美食软件 知乎 编辑:程序博客网 时间:2024/06/03 16:20
1.使用Object类的方法来实现线程之间的通信
为了实现线程通信,我们可以使用Object类提供的wait()、notify()、notifyAll()三个方法。调用wait()方法会释放对该同步监视器的锁定。这三个方法必须由同步监视器对象来调用,这可分成两种情况:
- 对于使用synchronized修饰的同步方法,因为该类的默认实例是(this)就是同步监视器,所以可以直接调用这三使用个方法。
- 对于synchronized修饰的同步代码块,同步监视器是synchronized括号里的对象,所以必须使用该对象调用这三个方法。
这次我们还是拿银行账户的取钱、存款来作为本文的例子演示。
假设系统中有两条线程,这两条线程分别代表取钱者和存钱者。现在系统有一种特殊的要求,系统要求存款者和取钱者不断的实现存款和取钱动作,而且要求每当存款者将钱存入指定账户后,取钱者立即将钱取走.不允许存款者两次存钱,也不允许取钱者两次取钱.
我们通过设置一个旗标来标识账户中是否已有存款,有就为true,没有就标为false。具体代码如下:
首先我们定义一个Account类,这个类中有取钱和存钱的两个方法,由于这两个方法可能需要并发的执行取钱、存钱操作,所有将这两个方法都修改为同步方法.(使用synchronized关键字)。
public class Account {private String accountNo;private double balance;//标识账户中是否有存款的旗标private boolean flag=false;public Account() {super();}public Account(String accountNo, double balance) {super();this.accountNo = accountNo;this.balance = balance;} public synchronized void draw (double drawAmount){try { if(!flag){ this.wait(); }else { //取钱 System.out.println(Thread.currentThread().getName()+" 取钱:"+drawAmount); balance=balance-drawAmount; System.out.println("余额 : "+balance); //将标识账户是否已有存款的标志设为false flag=false; //唤醒其它线程 this.notifyAll(); } } catch (Exception e) { e.printStackTrace(); }} public synchronized void deposit(double depositAmount){ try { if(flag){this.wait(); } else{ System.out.println(Thread.currentThread().getName()+"存钱"+depositAmount); balance=balance+depositAmount; System.out.println("账户余额为:"+balance); flag=true; //唤醒其它线程 this.notifyAll(); }} catch (Exception e) {// TODO: handle exceptione.printStackTrace();} }}
接下来创建两个线程类,分别为取钱和存钱线程!
取钱线程类:
public class DrawThread implements Runnable {private Account account;private double drawAmount;public DrawThread(Account account, double drawAmount) {super();this.account = account;this.drawAmount = drawAmount;}public void run() {for(int i=0;i<100;i++){ account.draw(drawAmount); }}}
存钱线程类:
public class depositThread implements Runnable{ private Account account; private double depositAmount; public depositThread(Account account, double depositAmount) {super();this.account = account;this.depositAmount = depositAmount;}public void run() {for(int i=0;i<100;i++){ account.deposit(depositAmount); }}}
最后我们测试一下这个取钱和存钱的操作!
public class TestDraw {public static void main(String[] args) {//创建一个账户Account account=new Account(); new Thread(new DrawThread(account, 800),"取钱者").start(); new Thread(new depositThread(account, 800),"存款者甲").start(); new Thread(new depositThread(account, 800),"存款者乙").start(); new Thread(new depositThread(account, 800),"存款者丙").start();}}
大致的输出结果:
存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者丙存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者丙存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者丙存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者丙存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0
由上述结果我们可以看到,存款者线程和取钱者线程交替执行的情形。至此简单的线程通信问题已经模拟完毕!
2.使用java.util.concurrent.locks下的Condition类来实现线程间的通信
如何程序不使用synchronized关键字来保持同步,而是直接适用Lock对像来保持同步,则系统中不存在隐式的同步监视器对象,也就不能使用wait()、notify()、notifyAll()来协调线程的运行.
当使用LOCK对象保持同步时,JAVA为我们提供了Condition类来协调线程的运行。关于Condition类,JDK文档里进行了详细的解释.,再次就不啰嗦了。
我们就拿Account类进行稍微的修改 一下吧!
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Account {//显示定义Lock对象private final Lock lock=new ReentrantLock();//获得指定Lock对象对应的条件变量 private final Condition con=lock.newCondition();private String accountNo;private double balance;//标识账户中是否有存款的旗标private boolean flag=false;public Account() {super();}public Account(String accountNo, double balance) {super();this.accountNo = accountNo;this.balance = balance;} public void draw (double drawAmount){//加锁lock.lock();try { if(!flag){// this.wait(); con.await(); }else { //取钱 System.out.println(Thread.currentThread().getName()+" 取钱:"+drawAmount); balance=balance-drawAmount; System.out.println("余额 : "+balance); //将标识账户是否已有存款的标志设为false flag=false; //唤醒其它线程// this.notifyAll(); con.signalAll(); } } catch (Exception e) { e.printStackTrace(); } finally{ lock.unlock(); }} public void deposit(double depositAmount){ //加锁 lock.lock(); try { if(flag){//this.wait(); con.await(); } else{ System.out.println(Thread.currentThread().getName()+"存钱"+depositAmount); balance=balance+depositAmount; System.out.println("账户余额为:"+balance); flag=true; //唤醒其它线程// this.notifyAll(); con.signalAll(); }} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}finally{lock.unlock();} }}
输出结果和上面是一样的! 只不过这里 显示的使用Lock对像来充当同步监视器,使用Condition对象来暂停指定线程,唤醒指定线程!
- JAVA 多线程通信 详解与举例
- java多线程举例
- Java多线程举例学习
- java 多线程 死锁 举例
- java NIOSocket 通信简要举例
- Java中多线程同步与通信
- Java中多线程同步与通信
- java多线程与线程间通信
- java多线程与线程间通信
- java多线程与线程间通信
- java多线程与线程间通信
- java多线程与线程间通信
- java多线程与线程间通信
- java多线程简单小举例
- JAVA——多线程举例
- vmstat命令详解与举例
- RSA算法详解与举例
- RSA算法详解与举例
- 2013.5打基础
- Java基础复习:文件拷贝
- Javascript常用的事件举例
- DNA的限制性内切酶酶切反应
- HDOJ_2203亲和串
- JAVA 多线程通信 详解与举例
- java学习感悟
- 网友发帖吐槽大学15类专业 高考志愿要慎重
- windbg 中 ChildEBP RetAddr MODULE!SYMBOL+0x0ffset 的含义
- VC6.0下的几个快捷键
- cout和wcout
- android activity是什么呢
- 网站验证码突然无法显示报错:Caused by: java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11Graph
- PLSQL Developer 一些设置