How Java uses code to simulate high concurrency operations

Java can find potential thread safety problems in our system in the fastest way by simulating high concurrency through code. Here we use Semaphore (semaphore) and CountDownLatch (latch) with ExecutorService (thread pool) to simulate, the main introduction is as follows:

1、Semaphore

        This class will be available after JDK 1.5

        Semaphore is a count-based semaphore. It can set a threshold. Based on this, multiple threads compete to obtain permission signals, and return them after completing their own applications. After the threshold is exceeded, the thread's application for permission signals will be blocked. Semaphore can be used to build some object pools, resource pools, etc., such as database connection pools, we can also create a Semaphore with a count of 1 as a mechanism similar to a mutex, which is also called a binary semaphore, which means Two mutually exclusive states.

2、CountDownLatch

        This class will be provided after JDK 1.5,

        The CountDownLatch class enables a thread to wait for other threads to complete their work before executing. For example, the main thread of the application may want to execute after the thread responsible for starting the framework services has started all the framework services.

        CountDownLatch is implemented by a counter whose initial value is the number of threads. Every time a thread completes its task, the value of the counter is decremented by 1. When the counter value reaches 0, it indicates that all threads have completed the task, and then the thread waiting on the latch can resume the task.

       As shown below:

The above two classes can be used in combination to achieve the effect of simulating high concurrency. The following code is used as an example:

 

package modules;

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

public class CountExample1 {

    // 请求总数
    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);
        //闭锁,可实现计数器递减
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                	//执行此方法用于获取执行许可,当总计未释放的许可数不超过200时,
                	//允许通行,否则线程阻塞等待,直到获取到许可。
                    semaphore.acquire();
                    add();
                    //释放许可
                    semaphore.release();
                } catch (Exception e) {
                    //log.error("exception", e);
                    e.printStackTrace();
                }
                //闭锁减一
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();//线程阻塞,直到闭锁值为0时,阻塞才释放,继续往下执行
        executorService.shutdown();
        log.info("count:{}", count);
    }

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

The above method simulates 5000 requests and a maximum of 200 concurrent operations at the same time. Observe the final results and find that each time the results are different, which are not in line with expectations. The results are as follows:

22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:4997
22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:5000
22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:4995
22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:4998

Final conclusion: the add method is not thread safe

So how to ensure the thread safety of the add method, you can modify the add method as follows:

private static void add() {
     count.incrementAndGet();
}

The execution result is as follows:

22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:5000
22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:5000
22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:5000
22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:5000
22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:5000
22:18:26.449 [main] INFO com.mmall.concurrency.example.count.CountExample1 - count:5000

Final conclusion: the modified add method is thread-safe

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324933695&siteId=291194637