Java笔记(二十)……线程间通信

时间:2023-03-08 18:18:21

概述

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

Java笔记(二十)……线程间通信

相关语句

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: }

Java笔记(二十)……线程间通信

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()

自定义线程名称