JAVA concurrent programming 3 _ synchronized keyword for thread synchronization and synchronized keyword

Source: Internet
Author: User

JAVA concurrent programming 3 _ synchronized keyword for thread synchronization and synchronized keyword

In the previous blog, I explained the JAVA thread memory model. For details, see JAVA concurrent programming 2 _ thread Security & memory model, the problem mentioned in the previous article solves the thread security problem when multiple threads share resources.

Unsafe thread Analysis

public class Test implements Runnable {private int i = 0;private int getNext() {return i++;}@Overridepublic void run() { // synchronizedwhile (true) {synchronized(this){if(i<10){System.out.println(getNext());}elsebreak;}}}public static void main(String[] args) {Test t = new Test();Thread t1 = new Thread(t);Thread t2 = new Thread(t);t1.start();t2.start();Thread.yield();}}


The difference from the previous Code is that the run method is modified by the synchronized keyword.

According to the analysis in the previous blog: when multiple threads access shared resources, the CPU takes turns to allocate the time occupied by each task, and the CPU scheduling is random, therefore, when a thread is accessing the variable, the CPU distributes the time slice to other threads. This will happen: the value of a variable read by a thread from the main memory has not been modified (or the main memory is refreshed after modification). The other thread obtains the CPU execution permission and reads the value of the change volume from the main memory. When the CPU execution right is returned to the first thread again, it will be executed at the previous interrupt (modifying variables, etc ), when the execution right is returned to the second thread, the value changed in the first thread cannot be seen. In short, it violates the thread memory visibility. Avoid the possible sequence of the first output as shown in (in fact, there are many possible cases, because I ++ is not a single atomic operation ):


I ++ corresponds to the following JVM commands, so another thread may modify this variable during this period.

4: aload_0

5: iconst_0

6: putfield #2 // Field I: I

To reflect the memory visibility, the synchronized keyword enables the code it protects to be accessed in serial mode (only one thread can access the code at a time ). Make sure that a thread can view the execution results of another thread in a predictable way.

Thread Synchronization

The lock mechanism provided by JAVA includes synchronous code blocks and synchronization methods.

Each Java object can be used as a synchronization Lock, which becomes an internal Lock or Monitor Lock ), will a thread automatically obtain the lock before it enters the synchronization belt? Will it release the lock when it is fast. The displacement path for obtaining the built-in lock is to enter the synchronous code block or method protected by the lock and the lock has not been obtained by other threads.

A Java built-in lock is equivalent to a mutex (mutex), meaning that at most one thread holds this lock. When thread A tries to obtain A lock held by thread B, thread A must wait or block and know that thread B releases the lock. If thread B never releases the lock, then thread A will wait forever.

Each time, only one thread can execute a code block with built-in lock protection. Therefore, the synchronization code block protected by this lock will be executed in an atomic manner, and multiple threads will not interfere with each other when executing this code block.

Atomicity: A group of statements are executed as an inseparable unit. It is impossible for any thread that executes the synchronization code block to see that other threads are executing the synchronization code block protected by the same lock.

Note: It doesn't mean that the synchronized code block or the synchronized method is an integral whole and an atomic one, because obviously there is no mutex between different locks.

Introduction of ticket purchase examples

The following is a program used to simulate ticket sales at the railway station. In theory, we want to sell a ticket numbered 1-10 in ascending order. The result is two windows (thread) as a result, some of the numbered tickets were sold twice, some were not sold out, and the numbered 0 tickets were sold out. Apparently, the result is incorrect.

Public class Test implements Runnable {private int I = 10; private void sale () {while (true) {if (I> 0) {try {Thread. sleep (10);} catch (InterruptedException e) {e. printStackTrace ();} System. out. println (Thread. currentThread () + "selling" + I + "tickets"); I --;} elsebreak ;}@overridepublic void run () {sale ();} public static void main (String [] args) {Test t = new Test (); Thread t1 = new Thread (t); Thread t2 = new Thread (t ); t1.start (); t2.start (); Thread. yield ();}}

The reason for this is that no synchronization lock is applied to resources accessed by multiple threads. We will perform thread synchronization to achieve the desired effect:

Synchronized code block:

Synchronized (lock) {// Synchronous Code}

Lock must be a variable of the reference type.

Use synchronized to synchronize code blocks:

Public class Test implements Runnable {private int I = 10; private void sale () {Object o = new Object (); while (true) {synchronized (o) {if (I> 0) {System. out. println (Thread. currentThread () + "selling" + I + "tickets"); I --;} elsebreak ;}}@ Overridepublic void run () {sale ();} public static void main (String [] args) {Test t = new Test (); Thread t1 = new Thread (t); Thread t2 = new Thread (t ); t1.start (); t2.start (); Thread. yield ();}}


Why? Why is the result still incorrect when the synchronous code block is used ?? Let's first look at the correct synchronization:

Public class Test implements Runnable {private int I = 10; Object o = new Object (); // usually used: /* static */byte [] lock = new byte [0]; private void sale () {while (true) {try {Thread. sleep (10);} catch (InterruptedException e) {e. printStackTrace ();} synchronized (o) {if (I> 0) {System. out. println (Thread. currentThread () + "selling" + I + "tickets"); I --;} elsebreak ;}}@ Overridepublic void run () {sale ();} public static void main (String [] args) {Test t = new Test (); Thread t1 = new Thread (t); Thread t2 = new Thread (t ); t1.start (); t2.start (); Thread. yield ();}

What is the thread synchronization principle here? Because any Java object can be used as a synchronization lock, the object o in the code above is a synchronization lock.

When a thread executes the synchronized code block, the thread attempts to lock the synchronization lock. If the synchronization lock has been locked, the thread cannot get the lock and the thread is blocked. If the synchronization lock is not locked, the thread locks the synchronization lock, holds the lock, and then executes the code block. If the code block ends normally or abnormally, the synchronization lock is unlocked.

The synchronization lock is held when the thread executes the synchronization code block. If other threads cannot obtain the lock, they cannot enter the synchronization code block (provided that the same lock is used). They can only wait for the lock to be released.

Now let's look back at the synchronization code block in the previous Code. Because the two threads use different locks (two objects are created), even if thread A is executing the synchronization code block, when thread 2 obtains the CPU execution right, it checks that this lock is not locked by other threads, so it does not have mutual exclusion and cannot achieve the effect of thread synchronization.

Synchronization Method

Use synchronized as a method of the keyword modifier class, so that the method becomes a synchronous method.

The result of directly changing the sale function to the synchronized method is that although tickets are not sold in disorder, only one thread is selling tickets. So make some adjustments:

Public class Test implements Runnable {private int I = 10; private void sale () {while (true) {try {Thread. sleep (10);} catch (InterruptedException e) {e. printStackTrace () ;}f () ;}} private synchronized void f () {if (I> 0) {System. out. println (Thread. currentThread () + "selling" + I + "tickets"); I --;} elsereturn ;}@ Overridepublic void run () {sale ();} public static void main (String [] args) {Test t = new Test (); Thread t1 = new Thread (t); Thread t2 = new Thread (t ); t1.start (); t2.start (); Thread. yield ();}}

Which object is the lock at this time?

When the modification method is a Class method, the synchronization lock is the Class object corresponding to this Class;

When modifying a common method, the synchronization lock is the current object, that is, this.

Experience: do not abuse the synchronized Method

In normal programming, in order to achieve thread synchronization, the abuse of the synchronized keyword often occurs without careful consideration. In the final analysis, the synchronization principle is not understood.

See the following code:

Public class Test implements Runnable {@ Override public void run () {f ();} public synchronized void f () {System. out. println (this);} public static void main (String [] args) {Test t1 = new Test (); Test t2 = new Test (); // f () the code in it cannot achieve the synchronization goal new Thread (t1 ). start (); new Thread (t2 ). start () ;}// Output // Test @ 2073b879 // Test @ d542094

According to the printed results, the function f () cannot be synchronized because the two threads use two synchronization locks. This tells us that we should not consider synchronized as a synchronous method and call it in different threads.


Note: The above code used Thread multiple times. the sleep (long) method is used to sleep the current thread for a while. This method will cause the current thread to give up the CPU execution right and be in the Time Waiting state. The CPU does not allocate Time slices to it. Because different machines may not be prone to the expected thread switching, this can force thread switching.

In addition, using sleep in synchronized code is invalid. Because the CPU does not allocate time slice for the thread after sleep, but the thread has obtained the synchronization lock at this time, even if it goes to bed, it will not commit the synchronization lock, other threads get CPU execution but suffer from being rejected without a synchronization lock. The status of the learning thread will be described later.


You may not be able to write code clearly. It is really difficult to express a thing clearly in words.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.