同步工具类使用

2019/04/29 JAVA

同步工具类使用–顺序循环打印ABC

同步工具类基础概念点击这里

1.synchronized

/**
 * 使用synchronized实现
 * 具体思路:
 *     1.线程t1唤醒t2,t2唤醒t3,t3唤醒t1;
 *     2.由于在唤醒过程中不能唤醒指定线程,所以
 *        2.1 使用notifyAll()方法唤醒所有的线程,然后多个线程去竞争锁;
 *        2.2 判断条件处使用while循环,当条件成立时,当前线程一直处于wait状态。
 */
static class Worker{
   private volatile int num = 1;

   public void loopA(String str){
      synchronized (this){
         while(num != 1){
            try {
               this.wait();
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
         System.out.println(str);
         num = 2;
         this.notifyAll();
      }
   }

   public void loopB(String str){
      synchronized (this){
         while(num != 2){
            try {
               this.wait();
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
         System.out.println(str);
         num = 3;
         this.notifyAll();
      }
   }

   public void loopC(String str){
      synchronized (this){
         while(num != 3){
            try {
               this.wait();
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
         System.out.println(str);
         num = 1;
         this.notifyAll();
      }
   }
}

static class ThreadABC implements Runnable{
   private Worker work;
   private String str;

   public ThreadABC(Worker work, String str){
      this.work = work;
      this.str = str;
   }

   @Override
   public void run() {
      for(int i=0;i<10;i++){
         if("A".equals(str)){
            work.loopA(str);
         }else if("B".equals(str)){
            work.loopB(str);
         }else if("C".equals(str)){
            work.loopC(str);
         }
      }
   }
}

public static void main(String[] args) {
   Worker w = new Worker();
   Thread t1 = new Thread(new ThreadABC(w, "A"));
   Thread t2 = new Thread(new ThreadABC(w, "B"));
   Thread t3 = new Thread(new ThreadABC(w, "C"));
   t1.start();
   t2.start();
   t3.start();
}

2.ReentrantLock + Condition

/**
 * 使用ReentrantLock + Condition实现
 * 具体思路:
 *     1.三个条件队列,t1唤醒t2,t2唤醒t3,t3唤醒t1;
 *     2.Condition可以指定需要唤醒的线程。
 */
static class Worker{
   private Lock lock = new ReentrantLock();
   private Condition c1 = lock.newCondition();
   private Condition c2 = lock.newCondition();
   private Condition c3 = lock.newCondition();
   private volatile int num = 1;

   public void loopA(String str){
      lock.lock();
      try{
         if(num != 1){
            c1.await();
         }
         System.out.println(str);
         num = 2;
         c2.signal();
      }catch (Exception e){
         e.printStackTrace();
      }finally {
         lock.unlock();
      }
   }

   public void loopB(String str){
      lock.lock();
      try{
         if(num != 2){
            c2.await();
         }
         System.out.println(str);
         num = 3;
         c3.signal();
      }catch (Exception e){
         e.printStackTrace();
      }finally {
         lock.unlock();
      }
   }

   public void loopC(String str){
      lock.lock();
      try{
         if(num != 3){
            c3.await();
         }
         System.out.println(str);
         num = 1;
         c1.signal();
      }catch (Exception e){
         e.printStackTrace();
      }finally {
         lock.unlock();
      }
   }
}

3.CyclicBarrier

/**
 * 使用CyclicBarrier实现,CyclicBarrier内部为ReentrantLock + Condition
 * 具体思路:
 *     1.使用三个栅栏,cb1和cb2需要等待两个线程,cb3需要等待3个线程;
 *     2.打印A的时候cb1,cb3等待;
 *     3.cb1等待,由于cb1需要等待两个线程,此时线程t1,t2都到了栅栏位置,可以执行下面的代码,打印B,并且cb2,cb3等待;
 *     4.cb2等待,由于cb2需要等待两个线程,此时线程t2,t3都到了栅栏位置,可以执行下面的代码,打印C,并且cb3等待;
 *     5.cb3等待了3次,此时t1,t2,t3都到了栅栏位置,打印A,进入下一个周期。
 */
static class Worker{
   CyclicBarrier cb1 = new CyclicBarrier(2);
   CyclicBarrier cb2 = new CyclicBarrier(2);
   CyclicBarrier cb3 = new CyclicBarrier(3);

   public void loopA(String str){
      try {
         System.out.println(str);
         cb1.await();
         cb3.await();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public void loopB(String str){
      try {
         cb1.await();
         System.out.println(str);
         cb2.await();
         cb3.await();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public void loopC(String str){
      try {
         cb2.await();
         System.out.println(str);
         cb3.await();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

4.Phaser

/**
 * 使用Phaser(移相器/阶段器)实现,Semaphore内部为AQS共享锁的实现
 * 具体思路:
 *     和CyclicBarrier类似
 */
static class Worker{
   Phaser p1 = new Phaser(2);
   Phaser p2 = new Phaser(2);
   Phaser p3 = new Phaser(3);

   public void loopA(String str){
      System.out.println(str);
      p1.arriveAndAwaitAdvance();
      p3.arriveAndAwaitAdvance();
   }

   public void loopB(String str){
      p1.arriveAndAwaitAdvance();
      System.out.println(str);
      p2.arriveAndAwaitAdvance();
      p3.arriveAndAwaitAdvance();
   }

   public void loopC(String str){
      p2.arriveAndAwaitAdvance();
      System.out.println(str);
      p3.arriveAndAwaitAdvance();
   }
}

5.Semaphore

/**
 * 使用Semaphore实现,Semaphore内部为AQS共享锁的实现
 * 具体思路:
 *     1.三个信号量对象,初始只有sp1有一个permits(许可);
 *     2.permits是指允许有多少个线程同步执行;
 *     3.permits值不能小于0,当等于0时,acquire()方法被阻塞,等待其他线程调用release()方法;
 *     4.当调用acquire()方法时阻塞,直到有一个许可可以获得,然后拿走一个许可,进行后面的逻辑;
 *     5.当调用release()方法时增加一个许可。
 */
static class Worker{
   private Semaphore sp1 = new Semaphore(1);
   private Semaphore sp2 = new Semaphore(0);
   private Semaphore sp3 = new Semaphore(0);

   public void loopA(String str){
      try {
         sp1.acquire();
         System.out.println(str);
         sp2.release();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public void loopB(String str){
      try {
         sp2.acquire();
         System.out.println(str);
         sp3.release();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public void loopC(String str){
      try {
         sp3.acquire();
         System.out.println(str);
         sp1.release();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

Search

    Table of Contents