概述

当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行

相关语句

wait():挂起线程,释放锁,相当于自动放弃了执行权限

notify():唤醒wait等待队列里的第一个线程

notifyAll():唤醒所有等待队列中的线程

他们都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁

相关问题

为什么这些操作线程的方法要定义在Object类中

因为这些方法是依赖于锁进行的,而锁又是任意对象,所以这些方法必须定义在Object中,才可以被任意对象的锁调用

为什么使用notifyAll而不是notify

因为notify唤醒的只是等待队列里的第一个线程,该线程不确定,有可能是对方线程,也有可能是本方线程,所以要使用notifyAll来唤醒所有线程,并配合while循环判断标记才能保证运行的正常

实例代码

   1: //定义一把枪

   2: class Gun

   3: {

   4:     int bullet;

   5:     boolean isEmpty;

   6:  

   7:     Gun()

   8:     {

   9:         bullet = 0;

  10:         isEmpty = true;

  11:     }

  12:  

  13:     //上子弹

  14:     synchronized void putBullet()

  15:     {

  16:         //之所以用while,是因为notifyAll会唤醒所有线程

  17:         //若唤醒了本方线程,则需要再判断一次条件,确保本方线程不会冲突

  18:         while(isEmpty != true)

  19:         {

  20:             try

  21:             {

  22:                 wait();

  23:             }

  24:             catch (Exception e)

  25:             {

  26:             }

  27:         }

  28:  

  29:         bullet+=7;

  30:         System.out.println("Put bullet : "+ bullet);

  31:         isEmpty = false;

  32:         //上满子弹后,唤醒shot线程发射子弹

  33:         notifyAll();

  34:     }

  35:  

  36:     //射出子弹

  37:     synchronized void shotBullet()

  38:     {

  39:         while(isEmpty != false)

  40:         {

  41:             try

  42:             {

  43:                 wait();

  44:             }

  45:             catch (Exception e)

  46:             {

  47:             }

  48:         }            

  49:         System.out.println("Shot bullet : "+bullet--);

  50:             

  51:         if(bullet == 0)

  52:         {

  53:             isEmpty = true;

  54:             //子弹打光之后,唤醒put线程继续上子弹

  55:             notifyAll();

  56:         }

  57:     

  58:     }

  59: }

  60: class PutBullet implements Runnable

  61: {

  62:     private Gun g;

  63:     PutBullet(Gun g)

  64:     {

  65:         this.g = g;

  66:     }

  67:     public void run()

  68:     {

  69:         while(true)

  70:         {

  71:             g.putBullet();

  72:         }

  73:     }

  74: }

  75:  

  76: class ShotBullet implements Runnable

  77: {

  78:     private Gun g;

  79:     ShotBullet(Gun g)

  80:     {

  81:         this.g = g;

  82:     }

  83:     public void run()

  84:     {

  85:         while(true)

  86:         {

  87:             g.shotBullet();

  88:         }

  89:     }

  90: }

  91:  

  92: class MutiThreadDemo 

  93: {

  94:     public static void main(String[] args) 

  95:     {

  96:         Gun g = new Gun();

  97:         new Thread(new PutBullet(g)).start();

  98:         new Thread(new ShotBullet(g)).start();

  99:         new Thread(new PutBullet(g)).start();

 100:         new Thread(new ShotBullet(g)).start();

 101:     }

 102: }

JDK1.5之后的升级

JDK1.5中提供了多线程的升级解决方案

将同步synchronized替换成Lock操作

将Object中的wait,notify,notifyAll替换成condition对象,该对象可以对Lock锁进行获取

lock_condition机制可以实现只唤醒对方线程,条理更清晰,所以也省去了循环判断标记的动作

代码如下:

   1: import java.util.concurrent.locks.*;

   2:  

   3: //定义一把枪

   4: class Gun

   5: {

   6:     private int bullet;

   7:     private boolean isEmpty;

   8:  

   9:     private Lock lock = new ReentrantLock();

  10:     

  11:     private Condition condition_put = lock.newCondition();

  12:     private Condition condition_shot = lock.newCondition();

  13:  

  14:     Gun()

  15:     {

  16:         bullet = 0;

  17:         isEmpty = true;

  18:     }

  19:  

  20:     //上子弹

  21:     void putBullet()

  22:     {

  23:         lock.lock();

  24:         try

  25:         {

  26:             //之所以用while,是因为notifyAll会唤醒所有线程

  27:             //若唤醒了本方线程,则需要再判断一次条件,确保本方线程不会冲突

  28:             if(!isEmpty)

  29:                 condition_put.await();

  30:  

  31:             bullet+=7;

  32:             System.out.println("Put bullet : "+ bullet);

  33:             isEmpty = false;

  34:             //上满子弹后,唤醒shot线程发射子弹

  35:             condition_shot.signal();

  36:         }

  37:         catch (InterruptedException e)

  38:         {

  39:         }

  40:         finally

  41:         {

  42:             //释放锁的动作一定完成

  43:             lock.unlock();

  44:         }

  45:  

  46:     }

  47:  

  48:     //射出子弹

  49:     void shotBullet()

  50:     {

  51:         lock.lock();

  52:         try

  53:         {

  54:             if(isEmpty)

  55:                 condition_shot.await();

  56:             System.out.println("Shot bullet : "+bullet--);

  57:                 

  58:             if(bullet == 0)

  59:             {

  60:                 isEmpty = true;

  61:                 //子弹打光之后,唤醒put线程继续上子弹

  62:                 condition_put.signal();

  63:             }

  64:         }

  65:         catch (InterruptedException e)

  66:         {

  67:         }

  68:         finally

  69:         {

  70:             lock.unlock();

  71:         }

  72:         

  73:     }

  74: }

  75: class PutBullet implements Runnable

  76: {

  77:     private Gun g;

  78:     PutBullet(Gun g)

  79:     {

  80:         this.g = g;

  81:     }

  82:     public void run()

  83:     {

  84:         while(true)

  85:         {

  86:             g.putBullet();

  87:         }

  88:     }

  89: }

  90:  

  91: class ShotBullet implements Runnable

  92: {

  93:     private Gun g;

  94:     ShotBullet(Gun g)

  95:     {

  96:         this.g = g;

  97:     }

  98:     public void run()

  99:     {

 100:         while(true)

 101:         {

 102:             g.shotBullet();

 103:         }

 104:     }

 105: }

 106:  

 107: class MutiThreadDemo2

 108: {

 109:     public static void main(String[] args) 

 110:     {

 111:         Gun g = new Gun();

 112:         new Thread(new PutBullet(g)).start();

 113:         new Thread(new ShotBullet(g)).start();

 114:         new Thread(new PutBullet(g)).start();

 115:         new Thread(new ShotBullet(g)).start();

 116:     }

 117: }

 118:  

停止线程

如何停止线程

只有一种,run方法结束

开启的多线程通常都是循环结构,可以通过修改循环条件来结束run方法

但是当线程挂起时,有时会执行不到循环条件,一直挂起,这样就不会结束,这时需要对冻结状态的线程进行清除

Thread类为我们提供了一种方法,即interrupt()方法,用于解除挂起状态,恢复到运行状态,所以我们既可以改变循环条件,也可以通过处理InterruptedException异常来结束循环,代码如下:

   1: import java.util.concurrent.locks.*;

   2:  

   3: //定义一把枪

   4: class Gun

   5: {

   6:     private int bullet;

   7:     private boolean isEmpty;

   8:  

   9:     private Lock lock = new ReentrantLock();

  10:     

  11:     private Condition condition_put = lock.newCondition();

  12:     private Condition condition_shot = lock.newCondition();

  13:  

  14:     Gun()

  15:     {

  16:         bullet = 0;

  17:         isEmpty = true;

  18:     }

  19:  

  20:     //上子弹

  21:     void putBullet() throws InterruptedException

  22:     {

  23:         lock.lock();

  24:         try

  25:         {

  26:             //之所以用while,是因为notifyAll会唤醒所有线程

  27:             //若唤醒了本方线程,则需要再判断一次条件,确保本方线程不会冲突

  28:             if(!isEmpty)

  29:                 condition_put.await();

  30:  

  31:             bullet+=7;

  32:             System.out.println("Put bullet : "+ bullet);

  33:             isEmpty = false;

  34:             //上满子弹后,唤醒shot线程发射子弹

  35:             condition_shot.signal();

  36:         }

  37:         finally

  38:         {

  39:             //释放锁的动作一定完成

  40:             lock.unlock();

  41:         }

  42:  

  43:     }

  44:  

  45:     //射出子弹

  46:     void shotBullet() throws InterruptedException

  47:     {

  48:         lock.lock();

  49:         try

  50:         {

  51:             if(isEmpty)

  52:                 condition_shot.await();

  53:             System.out.println("Shot bullet : "+bullet--);

  54:                 

  55:             if(bullet == 0)

  56:             {

  57:                 isEmpty = true;

  58:                 //子弹打光之后,唤醒put线程继续上子弹

  59:                 condition_put.signal();

  60:             }

  61:         }

  62:         finally

  63:         {

  64:             lock.unlock();

  65:         }

  66:         

  67:     }

  68: }

  69: class PutBullet implements Runnable

  70: {

  71:     private Gun g;

  72:     PutBullet(Gun g)

  73:     {

  74:         this.g = g;

  75:     }

  76:     public void run()

  77:     {

  78:         while(true)

  79:         {

  80:             try

  81:             {

  82:                 g.putBullet();

  83:             }

  84:             catch (InterruptedException e)

  85:             {

  86:                 break;

  87:             }

  88:             

  89:         }

  90:     }

  91: }

  92:  

  93: class ShotBullet implements Runnable

  94: {

  95:     private Gun g;

  96:     ShotBullet(Gun g)

  97:     {

  98:         this.g = g;

  99:     }

 100:     public void run()

 101:     {

 102:         while(true)

 103:         {

 104:             try

 105:             {

 106:                 g.shotBullet();

 107:             }

 108:             //对异常进行处理,以退出循环

 109:             catch (InterruptedException e)

 110:             {

 111:                 break;

 112:             }

 113:         }

 114:     }

 115: }

 116:  

 117: class MutiThreadDemo2

 118: {

 119:     public static void main(String[] args) 

 120:     {

 121:         Gun g = new Gun();

 122:         Thread t1 = new Thread(new PutBullet(g));

 123:         Thread t2 = new Thread(new ShotBullet(g));

 124:         Thread t3 = new Thread(new PutBullet(g));

 125:         Thread t4 = new Thread(new ShotBullet(g));

 126:  

 127:         t1.start();

 128:         t2.start();

 129:         t3.start();

 130:         t4.start();

 131:  

 132:         try

 133:         {

 134:             Thread.sleep(5000);

 135:         }

 136:         catch (Exception e)

 137:         {

 138:         }

 139:  

 140:         t1.interrupt();

 141:         t2.interrupt();

 142:         t3.interrupt();

 143:         t4.interrupt();

 144:     }

 145: }

 146:  

线程类的其他方法

setPriority(int num)

设置线程运行的优先级,效果不绝对,只是个概率问题

setDaemon(boolean b)

守护线程,也叫后台线程,意味着当前台线程结束时,后台线程无论是否挂起,都会退出线程

join()

当A线程执行到B的join方法时,会等待Join方法结束,再继续执行,join方法一般用来临时加入线程操作

toString()

自定义线程名称

Java笔记(二十)……线程间通信的更多相关文章

  1. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  2. Java多线程编程核心技术---线程间通信(二)

    通过管道进行线程间通信:字节流 Java提供了各种各样的输入/输出流Stream可以很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据,一个线程发送 ...

  3. Java多线程编程(6)--线程间通信(下)

      因为本文的内容大部分是以生产者/消费者模式来进行讲解和举例的,所以在开始学习本文介绍的几种线程间的通信方式之前,我们先来熟悉一下生产者/消费者模式.   在实际的软件开发过程中,经常会碰到如下场景 ...

  4. Java多线程编程核心技术---线程间通信(一)

    线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一.线程间通信可以使系统之间的交互性更强大,在大大提高CPU利用率的同时还会使程序员对各 ...

  5. Java并发——使用Condition线程间通信

    线程间通信 线程之间除了同步互斥,还要考虑通信.在Java5之前我们的通信方式为:wait 和 notify.Condition的优势是支持多路等待,即可以定义多个Condition,每个condit ...

  6. Java 里如何实现线程间通信(转载)

    出处:http://www.importnew.com/26850.html 正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程 ...

  7. Java 里如何实现线程间通信

    正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及到的知识点:thread.join(), object.w ...

  8. 【转】Java里如何实现线程间通信

    正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及到的知识点:thread.join(), object.w ...

  9. Java 中如何实现线程间通信

    世界以痛吻我,要我报之以歌 -- 泰戈尔<飞鸟集> 虽然通常每个子线程只需要完成自己的任务,但是有时我们希望多个线程一起工作来完成一个任务,这就涉及到线程间通信. 关于线程间通信本文涉及到 ...

随机推荐

  1. 11个有用的Linux命令

    Linux命令行吸引了大多数Linux爱好者.一个正常的Linux用户一般掌握大约50-60个命令来处理每日的任务.今天为你解释下面几个命令:sudo.python.mtr.Ctrl+x+e.nl.s ...

  2. Angular 动态生成html中 ng-click无效

    bodyApp.controller('customersCtrl', function ($scope, $http, cfpLoadingBar,$compile) { $scope.test = ...

  3. 捕获ClientDataSet.ApplyUpdates和SocketConnection异常

    核心提示:如何捕获ClientDataSet.ApplyUpdates的错误,不用ReconcileError... var cdsEmp:TClientDataSet; //保存 procedure ...

  4. bootstrap .col-md-6 文字居中问题处理

  5. IOS中如何判断APP是否安装后首次运行或升级后首次运行

    对于是否为首次安装的App可以使用如下方法来判断 [[NSUserDefaults standardUserDefaults] boolForKey:@"firstLaunch"] ...

  6. poj 2187 Beauty Contest

    Beauty Contest 题意:给你一个数据范围在2~5e4范围内的横纵坐标在-1e4~1e4的点,问你任意两点之间的距离的最大值的平方等于多少? 一道卡壳凸包的模板题,也是第一次写计算几何的题, ...

  7. codeforces edu round3

    B. The Best Gift  传送门:http://codeforces.com/problemset/problem/609/B Emily's birthday is next week a ...

  8. .net中的Array,ArrayList和List

    Array:任意类型,定长 ArrayList:任意类型,不定长 List:特定类型,不定长 Array和ArrayList是通过存储object类型实现可以存储任意类型数据,使用时需要拆箱和装箱

  9. The partner transaction manager has disabled its support for remote/network transactions.

    http://technet.microsoft.com/en-us/library/cc753510(WS.10).aspx

  10. DOS系统里,分屏显示目录的命令是什么??

    dir /sdir /pdir /w 我记得这三个都是我当年常用的命令,有分瓶的,有滚动时候每页停顿的,还有去掉详细信息的吧,, 可以放在一起使用.如dir /p/w /p是滚动时候中间停顿的,/w是 ...