Java multithreading concurrency (i)--semaphore,volatile,synchronized, Lock

Source: Internet
Author: User
Tags object object semaphore stub visibility

In concurrent programming, we typically encounter the following three problems: atomicity, visibility, order. Let's take a look at these three concepts in detail:

1. atomicity

Atomicity: That is, one operation or multiple operations are either executed completely and the execution process is not interrupted by any factor, or it is not executed.

  
A classic example is a bank account transfer problem.
2. Visibility

Visibility means that when multiple threads access the same variable, a thread modifies the value of the variable, and other threads can immediately see the modified value.

3. Order

Ordering: The order in which the program executes is executed in the order of the Code.
  

Semaphore

Introduction
The semaphore (Semaphore), sometimes called a semaphore, is a facility used in a multithreaded environment that coordinates individual threads to ensure that they are able to use public resources correctly and rationally.

A count semaphore. Conceptually, semaphores maintain a set of licenses. If necessary, block each acquire () before the license is available, and then obtain the license. Each release () adds a license that may release a blocked fetch. However, instead of using the actual license object, Semaphore only counts the number of available licenses and takes action accordingly. The thread that gets the semaphore can enter the code or wait. Obtain and release access licenses through Acquire () and release ().

Concept
The semaphore is divided into single-valued and multi-valued two, which can only be obtained by one thread, the latter of which may be obtained by several threads.

 以一个停车场运作为例。为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。

in this parking system, parking spaces are public resources, and each car is like a thread, and the gatekeeper acts as the semaphore.
code example:

 Public  class beautyseekbarview extends View {    PrivateSemaphore sepoolth=NewSemaphore (0);//Semaphore to solve concurrency problems@Override    protected void OnDraw(Canvas canvas) {//TODO auto-generated method stub        Super. OnDraw (canvas);floatPointx =0;floatPointy=getheight ()/2; Canvas.drawline (0+getpaddingleft (), Pointy, getwidth ()-//When the drawing is complete, the signal is released and can be followed up.Sepoolth.release ();
    //Set default location     Public void setpointlocation(Final intLocation) {NewThread (NewRunnable () {@Override             Public void Run() {Try{//wait for the signal, until you receive the signal released above, start the logicSepoolth.acquire (); }Catch(Interruptedexception e) {//TODO auto-generated catch blockE.printstacktrace (); }if(location>0&&pointlist!=NULL&&!pointlist.isempty ()) {Bitmappointx=pointlist.get (location-1);                    Postinvalidate ();    }}). Start (); }
Volatile

Two-tier semantics for 1.volatile keywords

Once a shared variable (a member variable of a class, a static member variable of a class) is modified by volatile, then there is the semantics:

1. The visibility of this variable is ensured by a thread that modifies the value of a variable, which is immediately visible to other threads.

2. command reordering is prohibited.
3. Using the volatile keyword forces the modified value to be immediately written to main memory;

In the Java garbage collection article, the allocation of memory at runtime of the JVM is described. One of the memory areas is the JVM virtual machine stack, each thread runs with a line stacks, and the line stacks saves the thread runtime variable value information. When a thread accesses an object, the value of the variable that corresponds to the heap memory is found first through the object's reference, then the concrete value of the heap memory variable is load into the thread local memory, a copy of the variable is created, and then the thread is no longer related to the object's value in the heap memory variable, but instead directly modifies the value of the At some point after the modification (before the thread exits), the value of the thread variable copy is automatically written back to the object in the heap variable. This changes the value of the object in the heap.
 
 For volatile-modified variables, the JVM virtual machine simply guarantees that the value from main memory load to the working memory of the thread is up-to-date

For example, if thread 1, thread 2 in the read,load operation, found that the value of count in main memory is 5, then the latest value will be loaded

After the thread 1 heap count is modified, it is write to main memory, and the count variable in main memory becomes 6

Thread 2 because the read,load operation has been performed, after the operation, the main memory will also be updated count of the variable value of 6

When two threads are modified with the volatile keyword in a timely manner, there is still a concurrency situation.

In general, the following 2 conditions are required to use volatile:

1) The write operation to the variable does not depend on the current value

2) The variable is not included in the invariant with other variables.

Synchronized

The implementation of synchronization is, of course, a lock, and the two basic tools for using locks in Java are synchronized and lock.

Always like synchronized, because it is very convenient to use. For example, to synchronize a method, simply add a synchronized keyword to the signature of the method.

// 未同步的方法publicvoidtest() {}// 同步的方法synchronizedvoid test() {}synchronized 也可以用在一个代码块上,看publicvoidtest() {     synchronized(obj) {          System.out.println("===");     }}

What is the difference between a synchronized and a code block?

Synchronized is used on the method signature (for example, test), and when a thread calls this method, it gets the object lock for that instance, and the other thread waits until the method ends. Object locks are released only when this method finishes executing. Other threads have the opportunity to seize the lock and execute the method test, but this should be based on the same object instance used by all the threads in order to achieve mutually exclusive behavior. Otherwise the Synchronized keyword will lose its meaning.

(However, if the method is a class method, that is, its modifier is static, then synchronized means that a thread that calls this method currently has a lock on that class, so long as that thread continues to run within the current method, other threads still can't get access to the method!) )

How synchronized is used in code blocks:synchronized(obj){//todo code here}

When a thread runs into that code block, it has an object lock on the Obj object, and if multiple threads share the same object object, then a mutex is created! In particular, when obj = = This represents an instance object that is currently calling the method. That

public void test() {     ...     synchronized(this) {          // todo your code     }     ...}

At this point, the effect is equal to

publicsynchronizedvoidtest() {     // todo your code}

With the synchronized code block, you can synchronize only the code that needs to be synchronized, which can greatly improve efficiency.

Summary:
There are two advantages to using the synchronized code block compared to the method:
1, can only be used to synchronize the use of
2, when used with Wait ()/notify ()/nitifyall (), it is more convenient

Wait () with notify ()/notifyall ()

These three methods are the method of the object, not the threading Method!
Wait (): Frees the owning object lock, the thread enters the waiting pool, frees the CPU, and the other waiting thread can preempt the lock, and the thread that obtains the lock can run the program. Unlike sleep (), when the thread calls this method, it sleeps for a period of time, temporarily releasing the CPU during hibernation, but does not release the object lock. That is, during hibernation, other threads still cannot get inside this code. The end of hibernation, the thread regain the CPU, execute the code. The biggest difference between wait () and sleep () is that wait () frees the object lock, and sleep () does not!

Notify (): This method wakes up the thread waiting for the call to wait (), which is actually a wake-up of the object lock, allowing the thread of wait () to have a chance to acquire an object lock. After calling notify (), the lock is not released immediately, but the current code continues to execute until the code in the synchronized is fully executed before the object lock is released. The JVM will dispatch a thread in the waiting thread to get the object lock and execute the code. It is important to note that wait () and notify () must be called in the synchronized code block.

Notifyall () is the wake-up of all waiting threads.

To illustrate this point, the following are examples:
Two threads print "A" "B" sequentially, printing a total of 10 times.

 Public  class Consumer implements Runnable {     @Override      Public synchronized void Run() {//TODO auto-generated method stub            intCount =Ten; while(Count >0) {synchronized(Test. obj) {System. Out.print ("B");                     Count--; Test. Obj.notify ();//Active Release object lock                      Try{Test. obj.wait (); }Catch(Interruptedexception e) {//TODO auto-generated catch blockE.printstacktrace (); }                }           }     }} Public  class produce implements Runnable {     @Override      Public void Run() {//TODO auto-generated method stub            intCount =Ten; while(Count >0) {synchronized(Test. obj) {//system.out.print ("Count =" + count);System. Out.print ("A");                     Count--; Test. Obj.notify ();Try{Test. obj.wait (); }Catch(Interruptedexception e) {//TODO auto-generated catch blockE.printstacktrace (); }                }           }     }}

The test classes are as follows:

publicclass Test {     publicstaticnew Object();     publicstaticvoidmain(String[] args) {            newnew Produce()).start();            newnew Consumer()).start();     }}

Here the static obj is used as the object of the lock, and when the thread produce starts (if produce first obtains the lock, then consumer waits), after printing "A", the lock is released and then blocked. Consumer get the object lock, print "B", then release the lock, block yourself, then produce will get the lock, then ... Keep looping until Count = 0. This allows thread synchronization to be achieved using synchronized and wait () and notify ().

In addition to the wait () and notify () collaboration to complete thread synchronization, using lock also accomplishes the same thing.

Reentrantlock and synchronized have the same concurrency and memory semantics, also include interrupt lock wait and timed lock wait, meaning that thread a if the object obj first obtained the lock, then thread B can wait for a specified period of time still cannot acquire the lock, then will automatically discard the lock.

However, since synchronized is implemented at the JVM level, the system can monitor the release of the lock, and Reentrantlock uses the code to implement it, the system cannot automatically release the lock, and you need to explicitly release the lock Lock.unlock () in the finally clause in the code.

For the same example, how does lock work?

Lock
 Public  class Consumer implements Runnable {     PrivateLock lock; Public Consumer(Lock Lock) { This.     lock = lock; }@Override      Public void Run() {//TODO auto-generated method stub            intCount =Ten; while(Count >0) {Try{Lock.lock ();                     Count--; System. Out.print ("B"); }finally{Lock.unlock ();//Active Release lock                      Try{Thread. Sleep ( theL); }Catch(Interruptedexception e) {//TODO auto-generated catch blockE.printstacktrace (); }                }           }     }} Public  class Producer implements Runnable{     PrivateLock lock; Public Producer(Lock Lock) { This.     lock = lock; }@Override      Public void Run() {//TODO auto-generated method stub            intCount =Ten; while(Count >0) {Try{Lock.lock ();                     Count--; System. Out.print ("A"); }finally{Lock.unlock ();Try{Thread. Sleep ( -L); }Catch(Interruptedexception e) {//TODO auto-generated catch blockE.printstacktrace (); }                }           }     }}

Calling code:

publicclass Test {     publicstaticvoidmain(String[] args) {           locknew ReentrantLock();           new Consumer(lock);           new Producer(lock);            new Thread(consumer).start();            new Thread( producer).start();     }}

Usage Recommendations:

In the case of small concurrency, using synchronized is a good choice, but in the case of high concurrency, its performance degradation is very serious, at this time Reentrantlock is a good solution.

Java multithreading concurrency (i)--semaphore,volatile,synchronized, Lock

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.