CountDownLunch、Semaphore

场景:主线程运行,到一定点之后,由于任务比较重,则线程执行,同时可以执行的线程数为n,等待每个线程都执行完毕后主线程继续往下执行;

  CountDownLunch即可实现计数操作,等待所有线程执行完毕后主线程开始执行;

  Semaphore即可控制共享资源的最大线程数,通过semaphore.acquire()来获取访问许可;通过semaphore.release()来释放许可;

简单的理解就是:比如百米接力赛,共有五个跑道,三组接力赛跑员,裁判发令枪响,比赛开始,直到最后一个选手跑完比赛才算结束;这里的接力棒就像是这里的信号量semaphore.acquire()和semaphore.release(),只有线程获取到信号量才可以开跑,当线程释放了信号量下一个等待线程才可以获取,只有直到最后一个线程执行完毕后,主线程才可以继续执行;

下面通过具体代码演示:

  下面代码中定义的一个抽象类,实现了CountDownLatch和Semaphore的组合使用;

package com.zl.concurrency.example.temp;

import com.zl.concurrency.example.ThreadPoolResource.ThreadPoolInstance;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * CountDownLunch公用模板
 *
 * @author zhagnlei
 * @ProjectName: MapDemo
 * @create 2018-09-14 16:59
 * @Version: 1.0
 * <p>Copyright: Copyright (zl) 2018</p>
 **/
@Slf4j
public abstract class AbstractCountDownLunchComm {
    protected int clientTotal ;
    protected int threadTotal ;
    private static final ExecutorService executorService = ThreadPoolInstance.getThreadPollInstance(5, 200, 0L);

    public void execute(int clientTotal, int threadTotal) throws Exception {
        this.clientTotal = clientTotal;
        this.threadTotal = threadTotal;
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i ++ ) {
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    definedMethods();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("exception"+e);
                }
                log.info("单执行完毕{}",Thread.currentThread().getId());
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("结束:{}","执行完毕!");
    }
    /**
     * @Description 自定义方法
     * @return void
     * @throws InterruptedException
     * @Author zhanglei
     * @Date 15:42 2018/9/16
     * @Param []
     **/
    public abstract void definedMethods() throws InterruptedException;
}

测试代码:


package com.zl.concurrency.example.atomic;


import com.zl.concurrency.annoations.ThreadSafe;
import com.zl.concurrency.example.temp.AbstractCountDownLunchComm;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicInteger;

/**
* java类简单作用描述
*
* @ProjectName: MapDemo
* @Package: com.zl.concurrency.code
* @ClassName: ${TYPE_NAME}
* @Description: java类作用描述
* @Author: zhanglie
* @CreateDate: 2018/9/11 21:35
* @UpdateUser: Zhanglei
* @UpdateDate: 2018/9/11 21:35
* @UpdateRemark: The modified content
* @Version: 1.0
* <p>Copyright: Copyright (c) 2018</p>
*/
@Slf4j
@ThreadSafe
public class AtomicIntegerExample extends AbstractCountDownLunchComm {
/** 请求总数 **/
public static int clientTotal = 10;
/** 同时并发执行的线程数 **/
public static int threadTotal = 2

public static AtomicInteger count = new AtomicInteger(0);

public static void main(String[] args) throws Exception {
try {
new AtomicIntegerExample().execute(clientTotal,threadTotal);
log.info("输出:{}",count);
} catch (Exception e) {
e.printStackTrace();
}
log.info("count:{}",count.get());
}


@Override
public void definedMethods() {
count.incrementAndGet();
     Thread.sleep(2000);
    }
}

  这里定义了10个请求总和,并发执行是2个,通过此方法来实现一个AtomicInteger的自增;即同时发送10个请求,分2个一批执行,每个执行都是对一个静态变量加1操作;

 

结果:

  可以看到,先是每个线程执行,执行后睡2s,当所有线程执行完毕后main线程输入总和;由于设置的并发是2,从时间上可以看出是2个2个同时输出;countDownLatch.countDown()操作相当于是在一个基数减一操作,countDownLatch.await()相当于阻塞主线程,当减到0后唤醒主线程;

 

posted @ 2018-12-17 15:42  zlAdmin  阅读(811)  评论(0)    收藏  举报