• 3-4 并发模拟-代码


    CountDownLatch,计数器向下减的一个闭锁。假设计数器的值cnt=3,CountDownLatch这个类可以阻塞线程,并保证线程在满足某种特定的条件下继续执行,这是CountDownLatch它可能起到的作用。

    信号量,Semaphore它可以阻塞进程,并且控制同一时间的请求的并发量。CountDownLatch和Semaphore在使用时通常会和线程池一起使用,后面我们会有单独的章节来介绍线程的调度以及使用的具体例子。这里我们先借助它们来实现并发的模拟。CountDownLatch它比较适合保证线程执行完之后再继续其他的处理,Semaphore它更适合控制同时并发的线程数,因此如果我们想模拟并发测试的时候,并在所有线程执行完输出一些结果,使用这两个线程结合起来是最好的。


    信号量要给出来允许并发的数目,同时并发的线程数。现在我们已经在线程池执行的时候引入了信号量,信号量每次做acquire()的时候semaphore.acquire();其实就是判断当前这个进程是否允许被执行,如果达到了一定的并发数之后,这个add()可能明显会被阻塞掉。当semaphore.acquire()能够返回出来值之后,当前add()它会执行,执行完了之后我们要释放当前这个进程。这样这个信号量它就引入完毕了。接下来我们在这个基础之上引入我们的闭锁。

                     try {
                         semaphore.acquire();
                         add();
                         semaphore.release();
                     } catch (Exception e) {
                         log.error("exception",e);
                     }

    这里面是我们执行一次线程的操作,在它执行完之后,我们调用一下countDownLatch.countDown();每执行完一个之后,它里面对应的这个计数值就会减一个,因此如果我们希望在所有线程都执行完之后打印当前计数的值,那么只需要在这个log之前加入countDownLatch的await()方法就可以了,因为这个方法可以保证之前的countDownLatch并且为0,它骤减为0的前提就是所有的进程都已经执行完,这个方法也需要捕捉异常的。通常当我们的线程池执行完之后,如果这个线程池之后不再使用了,这个时候我们需要关闭它。

    这个时候它返回的结果是一个不确定的结果,很有可能是错的,因此这个类是线程不安全的一个类。@NotThreadSafe这个注解代表大家不要模仿这个例子去做这个实现。本身它这里

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

    是线程不安全的写法。

    我们使用了线程池以及信号量以及计数器闭锁来把我们的并发模拟讲完了,这三个类java.util.concurrent.ExecutorService、java.util.concurrent.Semaphore、java.util.concurrent.CountDownLatch我们后期在线程调度部分会做特别的介绍,对应的线程调度的知识也是特别重要,大家后面学习时一定要特别注意。

    C:UsersHONGZHENHUAimoocconcurrencysrcmainjavacommmallconcurrencyConcurrencyTest.java

    package com.mmall.concurrency;
    
    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;
    
    @Slf4j
    @NotThreadSafe
    public class ConcurrencyTest { // 请求总数 public static int clientTotal = 5000;//1000个请求 // 同时并发执行的线程数 public static int threadTotal = 200;//允许并发的线程数是50 public static int count = 0; public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { executorService.execute(()-> { try { semaphore.acquire(); add(); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("count:{}",count); } private static void add() { count++; } }
  • 相关阅读:
    剑指Offer(Java版)第五十题:牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志, 写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看, 但却读不懂它的意思。例如,“student. a am I”
    剑指Offer(Java版)第四十九题:汇编语言中有一种移位指令叫做循环左移(ROL), 现在有个简单的任务,就是用字符串模拟这个指令的运算结果。 对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。 例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果, 即“XYZdefabc”。是不是很简单?OK,搞定它!
    【转载】Java 内存分配全面浅析
    【记】Linux下安装JDK1.7
    【ZooKeeper】典型应用场景概览
    正则表达式工具RegexBuddy
    【基础】RandomAccess
    【JNDI】Java Naming and Directory Interface
    【AOP】Cglib动态代理实现方式
    【事务】分布式事物原理
  • 原文地址:https://www.cnblogs.com/ZHONGZHENHUA/p/10041851.html
Copyright © 2020-2023  润新知