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

概述

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

thread6

相关语句

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

thread7

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

自定义线程名称

原文地址:https://www.cnblogs.com/ShawnWithSmallEyes/p/3379091.html