java multithreading - use volatile keyword carefully

The Java language contains two inherent synchronization mechanisms: synchronized blocks (or methods) and volatile variables. These two mechanisms are proposed to achieve code thread safety . Among them, Volatile variables are less synchronized (but sometimes simpler and less expensive), and their use is also more error-prone.

public volatile boolean exit = false;
When defining exit, a Java keyword volatile is used. The purpose of this keyword is to synchronize exit, that is to say, only one thread can modify the value of exit at the same time .

The volatile keyword is used to declare simple type variables, such as int, float, boolean and other data types. If these simple data types are declared volatile, operations on them become atomic. But this has certain limitations. For example, n in the following example is not atomic:

copy code
package junit.test;

public class ThreadVolatile extends Thread {
    public static volatile int n = 0;

    public void run() {
        for (int i = 0; i < 10; i++)
            try {
                n = n + 1;
                sleep( 3); // In order to make the running result more random, delay 3 milliseconds 

            } catch (Exception e) {
            }
    }

    public static void main(String[] args) throws Exception {

        Thread threads[] = new Thread[100 ];
         for ( int i = 0; i < threads.length; i++ )
             // Create 100 threads 
            threads[i] = new ThreadVolatile();
         for ( int i = 0; i < threads.length; i++ )
             // Run the 100 threads just created 
            threads[i].start();
         for ( int i = 0; i < threads.length; i++ )
             // Continue after 100 threads are executed 
            threads[i].join();
        System.out.println("n=" + ThreadVolatile.n);
    }
}
copy code

如果对n的操作是原子级别的,最后输出的结果应该为n=1000,而在执行上面代码时,很多时侯输出的n都小于1000,这说明n=n+1不是原子级别的操作。原因是声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:
n = n + 1;
n++;
如果要想使这种情况变成原子操作,需要使用synchronized关键字,如上的代码可以改成如下的形式:

copy code
package junit.test;

public class ThreadVolatile2 extends Thread {
    public static volatile int n = 0;

    public static synchronized void inc() {
        n++;
    }

    public void run() {
        for (int i = 0; i < 10; i++)
            try {
                inc(); // n = n + 1 改成了 inc();
                sleep(3); // 为了使运行结果更随机,延迟3毫秒

            } catch (Exception e) {
            }
    }

    public static void main(String[] args) throws Exception {

        Thread threads[] = new Thread[100];
        for (int i = 0; i < threads.length; i++)
            // 建立100个线程
            threads[i] = new ThreadVolatile2();
        for (int i = 0; i < threads.length; i++)
            // 运行刚才建立的100个线程
            threads[i].start();
        for (int i = 0; i < threads.length; i++)
            // 100个线程都执行完后继续
            threads[i].join();
        System.out.println("n=" + ThreadVolatile2.n);
    }
}
copy code

The above code changes n=n+1 to inc(), where the inc method uses the synchronized keyword for method synchronization. Therefore, be careful when using the volatile keyword, not as long as the simple type variable is modified with volatile, all operations on this variable are the original operations, when the value of the variable is determined by the previous one, such as n=n+1 , n++, etc., the volatile keyword will be invalid. Only when the value of the variable has nothing to do with its previous value, the operation of the variable is atomic. For example, n = m + 1, this is the original level. So be careful when using the volatile key. If you are not sure, you can use synchronized instead of volatile.

Guess you like

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