并发模拟代码 - CountDownLath、Semaphore

CountDownLatch

  1. 当前计数器的值为3;
  2. 线程a 调用了await()方法后,当前线程进入等待状态awaiting;
  3. 其他线程每次执行countDown()方法时,计数器就会减一,比如:线程1调用countDown()方法,计数器值为2,然后不停的执行,
  4. 只到计数器为0时,线程a 才继续执行。

如图:
在这里插入图片描述

我们可以看出CountDownLatch是java自带计数器,这个类可以阻塞线程,并保证线程满足某种特定的条件下再继续执行。保证线程执行完后,再进行其他的处理

Semaphore
可以阻塞线程,并且可以控制同一时间的请求的并发量,更适合控制同时进行的并发线程数

CountDownLatch和Semaphore 一般和线程池一起使用。

举例:
在这里插入图片描述

package com.mmall.concurrency.annoations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 课程里用来标记【线程不安全】的类或者写法
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NotThreadSafe {

    String value() default "";
}
package com.mmall.concurrency.atomic;

import com.mmall.concurrency.annoations.ThreadSafe;
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;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: wn
 * @Description: 线程不安全的类,反面案例
 * 重点在于理解CountDownLath 和 Semaphore 作用和用法
 * @Date: Created in 2019/1/11 11:45
 */
@Slf4j //日志
@ThreadSafe//自定义注解类
public class AtomicExample0 {

    // 请求总数
    public static int clientTotal = 5000;

    // 同时并发执行的线程数
    public static int threadTotal = 200;

    public static int count = 0;

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool(); //创建线程池
        final Semaphore semaphore = new Semaphore(threadTotal);  //semaphore信号量,允许并发的数目
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);//闭锁,计数器,传入请求总数
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    //信号量,acquire()时表示,当前线程数是否允许被执行,如果达到了一定并发数,这个add()方法将被阻塞
                    semaphore.acquire();
                    add();
                    semaphore.release();//信号量,执行完后,要释放当前线程release()
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();//没执行完一个线程,计数器减一
            });
        }
        countDownLatch.await();//countDownLatch.await()方法保证当前计数器为0,也就是所有的线程已经执行完
        executorService.shutdown();//关闭线程池
        log.info("count:{}", count);//执行完所有线程后,打印count值
    }

    private static void add() {
        count++;
    }
}


运行结果
5000
4989
4983
4805
运行结果不一定,不安全

重点理解CountDownLath 和 Semaphore 作用和用法

下面例子运行结果正确

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wangnanwlw/article/details/86293995
今日推荐