Thread security -- volatile

Keywords: Programming

volatile: when multiple threads operate and share data, data in memory can be visible;

@Slf4j
public class MyVolatile {

    public static void main(String[] args) {
        ThreadRun threadRun = new ThreadRun();
        new Thread(threadRun).start();

        log.info("begin----flag:{}",threadRun.flag);
        while (true){
            if (threadRun.flag){
                log.info("main ---flag:{}",threadRun.flag);
                break;
            }
        }
    }

    static class ThreadRun implements Runnable{
        private boolean flag = false;

        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            flag  = true;
            log.info("threadRun----flag:{}",flag);
        }

        public boolean isFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    }
}

The running result is as shown in the figure below. A program is running and cannot be ended.

Code analysis: after the main thread runs, another thread ThreadRun is opened. After the ThreadRun thread sleeps for 1000 milliseconds, the flag flag is changed to true. But for the main thread, the flag flag is always false, and the changed flag value of ThreadRun is invisible to the main thread, so the main thread is always in the while loop.

Next let's look at the use of the volatile keyword:

 static class ThreadRun implements Runnable{
        private volatile boolean flag = false;
		//Everything else is the same
}

The results of the code run have changed.

The volatile keyword comparison applies in this case. But it doesn't apply to counting

public class VolatileTest {
    //Total requests
    private static int clientTotal = 5000;
    //Total number of threads allowed to execute at the same time
    private static int threadTotal = 200;
    private static volatile int count = 0;

    public static void main(String[] args) throws InterruptedException {
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i=0;i<clientTotal;i++){
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        count++;
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("count="+count);
    }
}

Although count is decorated with volatile, the result of running the program is not the 5000 we expected. For specific reasons, please refer to another blog post Thread security -- atomic To understand. This article just thinks that the first example is a good illustration of the use scenario of volatile.

Posted by bznutz on Mon, 09 Dec 2019 23:28:35 -0800