The difference between volatile and synchronized
1, volatile is just a simple synchronization of the main memory area
2. There is no order in volatile execution, and dirty reading is inevitable (when the value of its own variable determines the value of this variable, n=n+1, n++, etc. (during self-operation))
3, will synchronize the main memory area
Used in multithreading, synchronizing variables. In order to improve efficiency, the thread copies a member variable (such as A) (such as B), and the access to A in the thread actually accesses B. Synchronization of A and B is only done for certain actions. So there is a situation where A and B are inconsistent. volatile is used to avoid this situation. Volatile tells the JVM that the variables it modifies do not retain copies, and directly access the main memory (that is, A)
======================= ==Separation line 1==================================
Copyright Notice: Please indicate the article in the form of a hyperlink when reprinting Original source and author information and this statement
http://aleung.blogbus.com/logs/32090434.html
In the Java memory model, there is main memory, and each thread also has its own memory (such as registers). For performance, a thread keeps a copy of the variable to be accessed in its own memory. In this way, the value of the same variable in the memory of one thread may be inconsistent with the value in the memory of another thread or the value in the main memory at a certain moment.
A variable declared as volatile means that the variable can be modified by other threads at any time, so it cannot be cached in thread memory. The following example shows the effect of volatile:
- public class StoppableTask extends Thread {
- private volatile boolean pleaseStop;
- public void run() {
- while (!pleaseStop) {
- // do some stuff...
- }
- }
- public void tellMeToStop() {
- pleaseStop = true;
- }
- }
If pleaseStop is not declared as volatile, and the thread checks its own copy when executing run, it cannot know in time that other threads have called tellMeToStop() to modify the value of pleaseStop.
Volatile cannot replace synchronized in general, because volatile cannot guarantee the atomicity of operations, even if it is only i++, it is actually composed of multiple atomic operations: read i; inc; write i, if multiple threads execute i++ at the same time, volatile can only It is guaranteed that the i they operate on is the same piece of memory, but it is still possible to write dirty data. If combined with the atomic wrapper classes added in Java 5, operations such as their increase do not need to be synchronized.
Reference:
http://www.javamex.com/tutorials/synchronization_volatile.shtml
http://www.javamex.com/tutorials/synchronization_volatile_java_5.shtml
http://www.ibm.com/developerworks/cn/java/j- jtp06197.html
==========================Separation Line 2==================== =============
I am afraid it is easiest to explain the difference between volatile and synchronized. Volatile is a variable modifier, while synchronized acts on a piece of code or method; see the following three get codes:
- int i1;
- int geti1() {return i1;}
- volatile int i2;
- int geti2()
- {return i2;}
- int i3;
- synchronized int geti3() {return i3;}
- geti1()
Get the value of i1 stored in the current thread. Multiple threads have multiple copies of the i1 variable, and these i1s can be different from each other. In other words, another thread may have changed the value of i1 in its thread, and this value may not be the same as the value of i1 in the current thread. In fact, Java has an idea called the "main" memory area, where the current "exact value" of a variable is stored. Each thread can have its own copy of the variable, and the value of this variable copy can be different from the one stored in the "main" memory area. So there is actually a possibility: the value of i1 in the "main" memory area is 1, the value of i1 in thread 1 is 2, the value of i1 in thread 2 is 3 - this changes them in both thread 1 and thread 2 The respective i1 value, and this change has not yet been passed to the "main" memory area or other threads.
And geti2() gets the i2 value of the "main" memory area. Variables decorated with volatile are not allowed to have copies of variables that differ from the "main" memory area. In other words, a variable that is volatile must be synchronized in all threads; any thread that changes its value, all other threads immediately get the same value. Of course, volatile-modified variable accesses consume a little more resources than normal variables, because it is more efficient for a thread to have its own copy of the variable.
Now that the volatile keyword has achieved data synchronization between threads, what should be synchronized for? Hehe, there are two differences between them. First, synchronized acquires and releases monitors—a well-known fact that monitors enforce a block of code to be executed by only one thread at a time if two threads use the same object lock. However, synchronized also synchronizes memory: in fact, synchronized synchronizes the entire thread's memory in the "main" memory area. Therefore, the execution of the geti3() method does the following steps:
1. The thread requests to acquire the lock of the object monitoring this object (assuming it is not locked, otherwise the thread waits until the lock is released)
2. The data in the thread memory is eliminated, from the "main" Read in the memory area (the Java virtual machine can optimize this step... [I don't know how to express it later, Khan])
3. The code block is executed
4. Any changes to the variable can now be safely written to the "main" memory area (although the geti3() method does not change the variable value)
5. The thread releases the object lock monitoring the this object
so volatile is only in thread memory and "main" memory. "The value of a variable is synchronized between memory, while synchronized synchronizes the value of all variables by locking and unlocking a monitor. Obviously synchronized consumes more resources than volatile.
==========================Separation line 3======================== ==========
The volatile keyword believes that readers who understand Java multithreading are well aware of its role. 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:
- package mythread;
- public class JoinThread extends Thread
- {
- public static volatile int n = 0 ;
- public void run()
- {
- for ( int i = 0 ; i < 10 ; i ++ )
- try
- {
- n = n + 1 ;
- 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 JoinThread();
- 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= " + JoinThread.n);
- }
- }
如果对n的操作是原子级别的,最后输出的结果应该为n=1000,而在执行上面积代码时,很多时侯输出的n都小于1000,这说明n=n+1不是原子级别的操作。原因是声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:
n = n + 1 ;
n ++ ;
如果要想使这种情况变成原子操作,需要使用synchronized关键字,如上的代码可以改成如下的形式:
- package mythread;
- public class JoinThread extends Thread
- {
- public static 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 ++ )
- // create 100 threads
- threads[i] = new JoinThread();
- 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= " + JoinThread.n);
- }
- }
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 simple type variables are 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.