返回首页 | 新开户送体验金的娱乐城

合作共赢、快速高效、优质的网站建设提供商

更多精品源码-尽在织梦模板-www.moke8.com

Java并发之CountDownLatch与CyclicBarrier和Semaphore的示例

时间:2017-09-22 编辑:admin

这篇文章首要介绍了Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解的相关材料,需求的朋友能够参阅下

Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解

在java 1.5中,供给了一些十分有用的辅佐类来协助我们进行并发编程,比方CountDownLatch,CyclicBarrier和Semaphore,今日我们就来学习一下这三个辅佐类的用法。

以下是本文目录纲要:

一.CountDownLatch用法
二.CyclicBarrier用法
三.Semaphore用法

若有不正之处请多多体谅,并欢迎批评指正。

一.CountDownLatch用法

CountDownLatch类坐落java.util.concurrent包下,运用它能够完结相似计数器的功用。比方有一个使命A,它要等候其他4个使命履行结束之后才干履行,此刻就能够运用CountDownLatch来完结这种功用了。

CountDownLatch类只供给了一个结构器:


public CountDownLatch(int count) { }; //参数count为计数值

然后下面这3个办法是CountDownLatch类中最重要的办法:


public void await() throws InterruptedException { };  //调用await()办法的线程会被挂起,它会等候直到count值为0才持续履行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()相似,只不过等候必定的时刻后count值还没变为0的话就会持续履行
public void countDown() { }; //将count值减1

下面看一个比如我们就清楚CountDownLatch的用法了:


public class Test {
   public static void main(String[] args) {  
     final CountDownLatch latch = new CountDownLatch(2);

     new Thread(){
       public void run() {
         try {
           System.out.println("子线程"+Thread.currentThread().getName()+"正在履行");
          Thread.sleep(3000);
          System.out.println("子线程"+Thread.currentThread().getName()+"履行结束");
          latch.countDown();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
       };
     }.start();

     new Thread(){
       public void run() {
         try {
           System.out.println("子线程"+Thread.currentThread().getName()+"正在履行");
           Thread.sleep(3000);
           System.out.println("子线程"+Thread.currentThread().getName()+"履行结束");
           latch.countDown();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
       };
     }.start();

     try {
       System.out.println("等候2个子线程履行结束...");
      latch.await();
      System.out.println("2个子线程现已履行结束");
      System.out.println("持续履行主线程");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
   }
}

履行成果:


线程Thread-0正在履行
线程Thread-1正在履行
等候2个子线程履行结束...
线程Thread-0履行结束
线程Thread-1履行结束
2个子线程现已履行结束
持续履行主线程

二.CyclicBarrier用法

字面意思回环栅门,经过它能够完结让一组线程等候至某个状况之后再悉数一同履行。叫做回环是由于当一切等候线程都被开释今后,CyclicBarrier能够被重用。我们暂时把这个状况就叫做barrier,当调用await()办法之后,线程就处于barrier了。

CyclicBarrier类坐落java.util.concurrent包下,CyclicBarrier供给2个结构器:


public CyclicBarrier(int parties, Runnable barrierAction) {
}

public CyclicBarrier(int parties) {
}

参数parties指让多少个线程或许使命等候至barrier状况;参数barrierAction为当这些线程都抵达barrier状况时会履行的内容。

然后CyclicBarrier中最重要的办法就是await办法,它有2个重载版别:


public int await() throws InterruptedException, BrokenBarrierException { };
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };

第一个版别比较常用,用来挂起当时线程,直至一切线程都抵达barrier状况再一同履行后续使命;

第二个版别是让这些线程等候至必定的时刻,如果还有线程没有抵达barrier状况就直接让抵达barrier的线程履行后续使命。

下面举几个比如就理解了:

假若有若干个线程都要进行写数据操作,而且只要一切线程都完结写数据操作之后,这些线程才干持续做后边的工作,此刻就能够运用CyclicBarrier了:


public class Test {
  public static void main(String[] args) {
    int N = 4;
    CyclicBarrier barrier = new CyclicBarrier(N);
    for(int i=0;i<N;i++)
      new Writer(barrier).start();
  }
  static class Writer extends Thread{
    private CyclicBarrier cyclicBarrier;
    public Writer(CyclicBarrier cyclicBarrier) {
      this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
      System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
      try {
        Thread.sleep(5000);   //以睡觉来模仿写入数据操作
        System.out.println("线程"+Thread.currentThread().getName()+"写入数据结束,等候其他线程写入结束");
        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }catch(BrokenBarrierException e){
        e.printStackTrace();
      }
      System.out.println("一切线程写入结束,持续处理其他使命...");
    }
  }
}

履行成果:


线程Thread-0正在写入数据...
线程Thread-3正在写入数据...
线程Thread-2正在写入数据...
线程Thread-1正在写入数据...
线程Thread-2写入数据结束,等候其他线程写入结束
线程Thread-0写入数据结束,等候其他线程写入结束
线程Thread-3写入数据结束,等候其他线程写入结束
线程Thread-1写入数据结束,等候其他线程写入结束
一切线程写入结束,持续处理其他使命...
一切线程写入结束,持续处理其他使命...
一切线程写入结束,持续处理其他使命...
一切线程写入结束,持续处理其他使命...

从上面输出成果能够看出,每个写入线程履行完写数据操作之后,就在等候其他线程写入操作结束。

当一切线程线程写入操作结束之后,一切线程就持续进行后续的操作了。

如果说想在一切线程写入操作完之后,进行额定的其他操作能够为CyclicBarrier供给Runnable参数:


public class Test {
  public static void main(String[] args) {
    int N = 4;
    CyclicBarrier barrier = new CyclicBarrier(N,new Runnable() {
      @Override
      public void run() {
        System.out.println("当时线程"+Thread.currentThread().getName());  
      }
    });

    for(int i=0;i<N;i++)
      new Writer(barrier).start();
  }
  static class Writer extends Thread{
    private CyclicBarrier cyclicBarrier;
    public Writer(CyclicBarrier cyclicBarrier) {
      this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
      System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
      try {
        Thread.sleep(5000);   //以睡觉来模仿写入数据操作
        System.out.println("线程"+Thread.currentThread().getName()+"写入数据结束,等候其他线程写入结束");
        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }catch(BrokenBarrierException e){
        e.printStackTrace();
      }
      System.out.println("一切线程写入结束,持续处理其他使命...");
    }
  }
}

运转成果:


线程Thread-0正在写入数据...
线程Thread-1正在写入数据...
线程Thread-2正在写入数据...
线程Thread-3正在写入数据...
线程Thread-0写入数据结束,等候其他线程写入结束
线程Thread-1写入数据结束,等候其他线程写入结束
线程Thread-2写入数据结束,等候其他线程写入结束
线程Thread-3写入数据结束,等候其他线程写入结束
当时线程Thread-3
一切线程写入结束,持续处理其他使命...
一切线程写入结束,持续处理其他使命...
一切线程写入结束,持续处理其他使命...
一切线程写入结束,持续处理其他使命...

从成果能够看出,当四个线程都抵达barrier状况后,会从四个线程中挑选一个线程去履行Runnable。

下面看一下为await指定时刻的作用:


public class Test {
  public static void main(String[] args) {
    int N = 4;
    CyclicBarrier barrier = new CyclicBarrier(N);

    for(int i=0;i<N;i++) {
      if(i<N-1)
        new Writer(barrier).start();
      else {
        try {
          Thread.sleep(5000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        new Writer(barrier).start();
      }
    }
  }
  static class Writer extends Thread{
    private CyclicBarrier cyclicBarrier;
    public Writer(CyclicBarrier cyclicBarrier) {
      this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
      System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
      try {
        Thread.sleep(5000);   //以睡觉来模仿写入数据操作
        System.out.println("线程"+Thread.currentThread().getName()+"写入数据结束,等候其他线程写入结束");
        try {
          cyclicBarrier.await(2000, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }catch(BrokenBarrierException e){
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName()+"一切线程写入结束,持续处理其他使命...");
    }
  }
}

履行成果:


线程Thread-0正在写入数据...
线程Thread-2正在写入数据...
线程Thread-1正在写入数据...
线程Thread-2写入数据结束,等候其他线程写入结束
线程Thread-0写入数据结束,等候其他线程写入结束
线程Thread-1写入数据结束,等候其他线程写入结束
线程Thread-3正在写入数据...
java.util.concurrent.TimeoutException
Thread-1一切线程写入结束,持续处理其他使命...
Thread-0一切线程写入结束,持续处理其他使命...
  at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
  at java.util.concurrent.CyclicBarrier.await(Unknown Source)
  at com.cxh.test1.Test$Writer.run(Test.java:58)
java.util.concurrent.BrokenBarrierException
  at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
  at java.util.concurrent.CyclicBarrier.await(Unknown Source)
  at com.cxh.test1.Test$Writer.run(Test.java:58)
java.util.concurrent.BrokenBarrierException
  at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
  at java.util.concurrent.CyclicBarrier.await(Unknown Source)
  at com.cxh.test1.Test$Writer.run(Test.java:58)
Thread-2一切线程写入结束,持续处理其他使命...
java.util.concurrent.BrokenBarrierException
线程Thread-3写入数据结束,等候其他线程写入结束
  at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
  at java.util.concurrent.CyclicBarrier.await(Unknown Source)
  at com.cxh.test1.Test$Writer.run(Test.java:58)
Thread-3一切线程写入结束,持续处理其他使命...

上面的代码在main办法的for循环中,成心让最终一个线程发动推迟,由于在前面三个线程都抵达barrier之后,等候了指定的时刻发现第四个线程还没有抵达barrier,就抛出反常并持续履行后边的使命。

别的CyclicBarrier是能够重用的,看下面这个比如:


/**
 * Java学习沟通QQ群:589809992 我们一同学Java!
 */
public class Test {
  public static void main(String[] args) {
    int N = 4;
    CyclicBarrier barrier = new CyclicBarrier(N);

    for(int i=0;i<N;i++) {
      new Writer(barrier).start();
    }

    try {
      Thread.sleep(25000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    System.out.println("CyclicBarrier重用");

    for(int i=0;i<N;i++) {
      new Writer(barrier).start();
    }
  }
  static class Writer extends Thread{
    private CyclicBarrier cyclicBarrier;
    public Writer(CyclicBarrier cyclicBarrier) {
      this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
      System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
      try {
        Thread.sleep(5000);   //以睡觉来模仿写入数据操作
        System.out.println("线程"+Thread.currentThread().getName()+"写入数据结束,等候其他线程写入结束");

        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }catch(BrokenBarrierException e){
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName()+"一切线程写入结束,持续处理其他使命...");
    }
  }
}

履行成果:


线程Thread-0正在写入数据...
线程Thread-1正在写入数据...
线程Thread-3正在写入数据...
线程Thread-2正在写入数据...
线程Thread-1写入数据结束,等候其他线程写入结束
线程Thread-3写入数据结束,等候其他线程写入结束
线程Thread-2写入数据结束,等候其他线程写入结束
线程Thread-0写入数据结束,等候其他线程写入结束
Thread-0一切线程写入结束,持续处理其他使命...
Thread-3一切线程写入结束,持续处理其他使命...
Thread-1一切线程写入结束,持续处理其他使命...
Thread-2一切线程写入结束,持续处理其他使命...
CyclicBarrier重用
线程Thread-4正在写入数据...
线程Thread-5正在写入数据...
线程Thread-6正在写入数据...
线程Thread-7正在写入数据...
线程Thread-7写入数据结束,等候其他线程写入结束
线程Thread-5写入数据结束,等候其他线程写入结束
线程Thread-6写入数据结束,等候其他线程写入结束
线程Thread-4写入数据结束,等候其他线程写入结束
Thread-4一切线程写入结束,持续处理其他使命...
Thread-5一切线程写入结束,持续处理其他使命...
Thread-6一切线程写入结束,持续处理其他使命...
Thread-7一切线程写入结束,持续处理其他使命...

从履行成果能够看出,在初度的4个线程跳过barrier状况后,又能够用来进行新一轮的运用。而CountDownLatch无法进行重复运用。

三.Semaphore用法

Semaphore翻译成字面意思为 信号量,Semaphore能够控一同拜访的线程个数,经过 acquire() 获取一个答应,如果没有就等候,而 release() 开释一个答应。

Semaphore类坐落java.util.concurrent包下,它供给了2个结构器:


public Semaphore(int permits) {     //参数permits表明答应数目,即一同能够答应多少线程进行拜访
  sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {  //这个多了一个参数fair表明是否是公正的,即等候时刻越久的越先获取答应
  sync = (fair)? new FairSync(permits) : new NonfairSync(permits);
}

下面说一下Semaphore类中比较重要的几个办法,首先是acquire()、release()办法:


public void acquire() throws InterruptedException { }   //获取一个答应
public void acquire(int permits) throws InterruptedException { }  //获取permits个答应
public void release() { }     //开释一个答应
public void release(int permits) { }  //开释permits个答应

acquire()用来获取一个答应,若无答应能够取得,则会一向等候,直到取得答应。

release()用来开释答应。留意,在开释答应之前,必须先获取得答应。

这4个办法都会被堵塞,如果想当即得到履行成果,能够运用下面几个办法:


public boolean tryAcquire() { };  //测验获取一个答应,若获取成功,则当即回来true,若获取失利,则当即回来false
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException { }; //测验获取一个答应,若在指定的时刻内获取成功,则当即回来true,不然则当即回来false
public boolean tryAcquire(int permits) { }; //测验获取permits个答应,若获取成功,则当即回来true,若获取失利,则当即回来false
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { }; //测验获取permits个答应,若在指定的时刻内获取成功,则当即回来true,不然则当即回来false

别的还能够经过availablePermits()办法得到可用的答应数目。

下面经过一个比如来看一下Semaphore的具体运用:

假若一个工厂有5台机器,但是有8个工人,一台机器一同只能被一个工人运用,只要运用完了,其他工人才干持续运用。那么我们就能够经过Semaphore来完结:


/**
 * Java学习沟通QQ群:589809992 我们一同学Java!
 */
public class Test {
  public static void main(String[] args) {
    int N = 8;      //工人数
    Semaphore semaphore = new Semaphore(5); //机器数目
    for(int i=0;i<N;i++)
      new Worker(i,semaphore).start();
  }

  static class Worker extends Thread{
    private int num;
    private Semaphore semaphore;
    public Worker(int num,Semaphore semaphore){
      this.num = num;
      this.semaphore = semaphore;
    }

    @Override
    public void run() {
      try {
        semaphore.acquire();
        System.out.println("工人"+this.num+"占用一个机器在出产...");
        Thread.sleep(2000);
        System.out.println("工人"+this.num+"开释出机器");
        semaphore.release();      
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

履行成果:


工人0占用一个机器在出产...
工人1占用一个机器在出产...
工人2占用一个机器在出产...
工人4占用一个机器在出产...
工人5占用一个机器在出产...
工人0开释出机器
工人2开释出机器
工人3占用一个机器在出产...
工人7占用一个机器在出产...
工人4开释出机器
工人5开释出机器
工人1开释出机器
工人6占用一个机器在出产...
工人3开释出机器
工人7开释出机器
工人6开释出机器

下面对上面说的三个辅佐类进行一个总结:

1)CountDownLatch和CyclicBarrier都能够完结线程之间的等候,只不过它们侧重点不同:

CountDownLatch一般用于某个线程A等候若干个其他线程履行完使命之后,它才履行; 而CyclicBarrier一般用于一组线程相互等候至某个状况,然后这一组线程再一同履行; 别的,CountDownLatch是不能够重用的,而CyclicBarrier是能够重用的。

2)Semaphore其实和锁有点相似,它一般用于操控对某组资源的拜访权限。

以上就是Java并发之CountDownLatch与CyclicBarrier和Semaphore的示例的具体内容,更多请重视其它相关文章!


浏览:

网站建设

流程

    网站建设流程