zoukankan      html  css  js  c++  java
  • 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()

    自定义线程名称

  • 相关阅读:
    狡猾的商人
    差分约束系统
    【模板】负环
    关于Java8的精心总结
    rabbitmq+sleuth+zinkip 分布式链路追踪
    Linux下一只五颜六色的「猫」
    整理 Linux下列出目录内容的命令
    从封装变化的角度看设计模式——组件协作
    从封装变化的角度看设计模式——接口隔离
    从封装变化的角度看设计模式——对象创建
  • 原文地址:https://www.cnblogs.com/ShawnWithSmallEyes/p/3379091.html
Copyright © 2011-2022 走看看