1 What is a concurrency Issue.
Concurrent problems occur when multiple processes or threads access the same resource at the same time (or in the same period).
A typical example is a bank with two operators operating the same account at the same time. For example, a, B operators simultaneously read a balance of 1000 yuan account, a operator for the account increase of 100 yuan, B operator at the same time for the account minus 50 yuan, a first submitted, b after the Submission. The final actual account balance is 1000-50 = 950 yuan, but should be 1000+100-50=1050. This is a typical concurrency Problem. How to solve? Locks can be Used.
- Usage 1
public class Test{public synchronized void print () { ...;} }
A thread executes the print () method, and the object is Locked. Other threads will not be able to execute all synchronized blocks of the Object.
- Usage 2
public class test{public void print () { synchronized (this) {//lock This object ... ;}} }
The same usage 1, but more to reflect the essence of synchronized Usage.
- Usage 3
public class test{ Private String a = "Test"; public void print () { synchronized (a) {//lock A object ... ; } } public synchronized void T () { ...;//this Synchronization code block is not locked because of print (). }}
Executing print () Locks the object a, noting that it is not locked for the test object, which means that the other synchronized methods of the test object are not locked for print (). When the synchronization code block finishes executing, the lock on A is Released.
To lock the code block of an object without affecting the high-performance notation of other synchronized blocks of the object:
public class test{ Private byte[] lock = new byte[0]; public void print () { synchronized (lock) { ...; } } public synchronized void T () { ...; }}
- Locks for static methods
public class Test{public synchronized static void execute () { ...; }}
Effect with
public class Test{public static void execute () { synchronized (testthread.class) { ...;}} }
3 locks in Java and queues the Toilet.
A lock is a way to block other processes or threads from accessing resources, which means that locked resources cannot be accessed by other Requests. In java, the sychronized keyword is used to lock an object. Like what:
public class Mystack { int idx = 0; Char [] data = new char[6]; Public synchronized void push (char c) { data[idx] = c; idx++; } Public synchronized char pop () { idx--; return data[idx]; } public static void main (String Args[]) { mystack m = new Mystack (); /** the following object M is Locked. Strictly speaking, all synchronized blocks of the object m are Locked. If there is another thread t that tries to access m, then T cannot execute the push and pop methods of the M object . * /m.pop ();//object m is Locked. }}
Java's locking unlock is exactly the same as many people queuing up for a public toilet. The first man went in and locked the door from the inside, others had to wait in Line. The door will open (unlocked) when the first person is Finished. The second man went in, and he locked the door from the inside, and the others kept waiting in Line.
The toilet theory can be easily understood: a person enters a toilet seat, the toilet seat will be locked, but will not cause another toilet seat is also locked, because a person can not squat in the two toilet seat at the same time. For Java it is said that the lock in Java is for the same object, not for class. Look at the following example:
MYSTATCK m1 = new Mystack (); Mystatck m2 = new Mystatck (); m1.pop (); m2.pop ();
Locks on M1 objects do not affect M2 locks, because they are not the same toilet bit. That is, assuming that there are 3 threads t1,t2,t3 Operation m1, then these 3 threads can only be queued on M1 and so on, assuming that the other 2 threads t8,t9 in operation m2, then T8,T9 will only wait on m2. And T2 and T8 are not related, even if the M2 on the lock released, t1,t2,t3 may still be queued on the m1. Reason without it, not the same toilet-ear.
Java cannot add two locks to a block of code at the same time, unlike the database lock mechanism, where the database can add several different locks to a single record, see:
Http://hi.baidu.com/dapplehou/blog/item/b341a97744fe6616b151b9a3.html
4 When is the lock released?
generally, after executing the synchronization code block (locked code block), release the lock, or you can use the wait () method to release the lock halfway. Wait () way is like squatting in the toilet to half, suddenly found that the sewer blocked, had to come out to stand aside, so that the sewer master (ready to execute a thread of notify) into the toilet, dredge finished, the master shouted: "has been repaired" (notify), The comrade who had just come out heard the line Again. Attention ah, must wait for the teacher to come out ah, the master does not come out, who also cannot enter. That is, after the notify, not the other threads can immediately enter the blockade area activity, but must also wait for the notify code in the blocking area after the completion of the lock to release, the other threads can enter.
Here is the wait with the Notify Code example:
Public synchronized char pop () { Char c; While (buffer.size () = = 0) { try { this.wait ();//out of the toilet place } catch (interruptedexception e) { //ignore it: . } } c = ((Character) buffer.remove (buffer.size ()-1)). Charvalue (); Return c;} Public synchronized void push (char C) { this.notify ();//notifies Those wait () threads to Re-queue. Note: just notify them to Re-queue. Character charobj = new Character (c); Buffer.addelement (charobj);} After execution, release the Lock. Those queued threads are ready to come in.
Go a little Deeper.
Because the wait () operation and halfway out of the comrades will not be in line before the Notify signal, he will be watching the queue of people (including the plumber in it). Note that the master of Plumbing can not cut the queue, but also with those who go to the toilet in line, not to say that a person squat half out, repair the plumber can suddenly come out and then immediately rushed in to repair, he will be in line with the people who are fair competition, because he is also a normal thread. If the plumbing master in the back, then the front of the people in, found plugging, wait, and then out to stand aside, and then go in a, wait, out, stand aside, only to the master to go in to perform notify. In this way, a moment of kung fu, lined up next to stand a bunch of people, waiting for Notify.
finally, the master went in, then notify, next?
1. A wait person (thread) is Notified. 2. Why was he told that he was not the other wait person? Depends on the jvm. we cannot prejudge which one will be notified. In other words, priority is not necessarily a priority to wake up, waiting for a long time is not necessarily a priority to wake up, all unpredictable! (of course, If you know the implementation of the JVM , you can predict it.) 3. He (the thread being notified) wants to queue up again. 4. Will he be ranked in the first position of the team? The answer is: not necessarily. Is he going to end up in line? And not Necessarily. But if the thread has a higher priority set, then the probability of his being in front of it is quite large. 5. When it is his turn to re-enter the toilet, he will proceed from the last wait () and will not be re-executed. Disgusting Point said is, he will continue Lababa, will not Re-pull. 6. If the master Notifyall (). Then all the people who had come out of the pile were re-queued. The order is Unknown.
The Java DOC says that the awakened threads'll is not being able to proceed until the current thread relinquishes the lock on this object (the thread that wakes up cannot be executed until the current thread releases the Lock.)
It is obvious that this is explained by the Toilet-bit Theory.
5 Use of lock
Use the Synchronized keyword to lock the resource. You can also use the lock Keyword. It's What's New in JDK1.5. Use the Following:
Class Boundedbuffer {final Lock lock = new Reentrantlock (); Final Condition notfull = lock.newcondition (); Final Condition notempty = lock.newcondition (); Final object[] items = new object[100]; int putptr, takeptr, count; public void put (Object X) throws Interruptedexception {lock.lock (); Try {while (count = = Items.length) notfull.await (); items[putptr] = x; if (++putptr = = Items.length) Putptr = 0; ++count; Notempty.signal (); } finally {lock.unlock (); }} public Object take () throws Interruptedexception {lock.lock (); Try {while (count = = 0) notempty.await (); Object x = items[takeptr]; if (++takeptr = = Items.length) Takeptr = 0; --count; Notfull.signal (); Return x; } finally {lock.unlock (); } } }
(note: This is an example of javadoc, an implementation example of a blocking queue.) The so-called blocking queue is a queue that, if full or empty, causes the thread to block waiting. The Arrayblockingqueue in Java provides a ready-made blocking queue and does not need to write a specific one. )
The code between the Lock.lock () and Lock.unlock () of an object will be Locked. This way is better than the Synchronize where? In a nutshell, the threads for wait are Categorized. Using the toilet theory to describe, it is those who squat half and out of the toilet to wait for the reason may be different, some because the toilet is blocked, some because the toilet is out of water. Notice (notify), you can shout: because the toilet is blocked and waiting to come back to the queue (for example, The toilet jam problem is solved), or shout, because the toilet is not water and waiting to come back to the queue (such as the toilet is not water problem solved). This can be controlled more finely. Unlike Synchronize's wait and notify, whether the toilet is clogged or the toilet is not water can only shout: just waiting to come in line! If the queue of people came in a look, found that the original is only a toilet jam problem solved, and their desire to solve the problem (toilet no water) has not been resolved, had to go back to wait (wait), white come in turn a circle, wasting time and Resources.
Lock mode corresponds to Synchronized:
Lock |
Await |
Signal |
Signalall |
Synchronized |
Wait |
Notify |
Notifyall |
Note: do not call wait, notify, notifyall in Lock-mode blocks
6 using pipelines for inter-thread communication
The principle is Simple. Two threads, one operation pipedinputstream, one operation Pipedoutputstream. PipedOutputStream writes the data in buffer first, and if the buffer is full, this thread is wait. PipedInputStream reads the data in buffer, and if buffer has no data, this thread wait.
The blocking queue in jdk1.5 enables the same Functionality.
- Example 1 This example is really just a single thread, not to mention the communication between threads, but it is worth looking at.
Http://hi.baidu.com/ecspell/blog/item/7b02d3133ab555005aaf53f5.html
Package Io;import java.io.*;p ublic class pipedstreamtest {public static void main (string[] Args) {pipedoutputs Tream ops=new PipedOutputStream (); PipedInputStream pis=new PipedInputStream (); Try{ops.connect (pis);//implement Pipeline Connection new Producer (ops). run (); New Consumer (pis). Run (); }catch (Exception E) {e.printstacktrace (); }}}//producer class Producer implements Runnable{private PipedOutputStream ops; Public Producer (pipedoutputstream Ops) {this.ops=ops; } public void Run () {try{ops.write ("hell,spell". getBytes ()); Ops.close (); }catch (Exception E) {e.printstacktrace ();} }}//consumer class Consumer implements Runnable{private PipedInputStream pis; Public Consumer (pipedinputstream Pis) {this.pis=pis; } public void Run () {try{byte[] bu=new byte[100]; int Len=pis.read (bu); System.ouT.println (new String (bu,0,len)); Pis.close (); }catch (Exception E) {e.printstacktrace ();} }}
- Example 2 a little change to the above program is two THREADS.
Package Io;import java.io.*;p ublic class pipedstreamtest {public static void main (string[] Args) {pipedoutputs Tream ops=new PipedOutputStream (); PipedInputStream pis=new PipedInputStream (); Try{ops.connect (pis);//implement pipe connection Producer p = new Producer (ops); New Thread (p). Start (); Consumer C = new Consumer (pis); New Thread (c). Start (); }catch (Exception E) {e.printstacktrace (); }}}//producer class Producer implements Runnable{private PipedOutputStream ops; Public Producer (pipedoutputstream Ops) {this.ops=ops; } public void run () {try{for (;;) {ops.write ("hell,spell". getBytes ()); Ops.close (); }}catch (Exception E) {e.printstacktrace ();} }}//consumer class Consumer implements Runnable{private PipedInputStream pis; Public Consumer (pipedinputstream Pis) {this.pis=pis; } public void Run () {try{for (;;) {byte[] bu=new byte[100]; int Len=pis.read (bu); System.out.println (new String (bu,0,len)); } pis.close (); }catch (Exception E) {e.printstacktrace ();} }}
- Example 3. This example is more in the application
Import java.io.*; public class Pipedio {//the contents of the Sendfile file are copied to the Receiverfile file after the program is run public static void main (String Args[]) {tr Y{//structure Read-write Pipeline Flow object PipedInputStream pis=new PipedInputStream (); PipedOutputStream pos=new PipedOutputStream (); Implement Association Pos.connect (pis); Constructs two threads, and Starts. New Sender (pos, "c:\\text2.txt"). start (); New Receiver (pis, "c:\\text3.txt"). start (); }catch (ioexception e) {System.out.println ("Pipe Error" + e); }}}//thread sent class sender extends Thread{pipedoutputstream pos; File file; Constructor method Sender (pipedoutputstream pos, String fileName) {this.pos=pos; File=new File (fileName); }//thread Run method public void Run () {try{//read file contents FileInputStream fs=new FileInputStream (file); int data; While ((data=fs.read ())!=-1) {//write pipeline start Pos.write (data); } pos.close (); } catch (ioexception e) {System.out.println ("Sender Error" +e); }}}//thread Read class Receiver extends Thread{pipedinputstream pis; File file; Construction method Receiver (pipedinputstream pis, String fileName) {this.pis=pis; File=new File (fileName); }//thread run public void run () {try {//write file stream object Fil Eoutputstream fs=new FileOutputStream (file); int data; Read while ((data=pis.read ())!=-1) {//write to local file from end of pipe Fs.write (data); } pis.close (); } catch (ioexception e) {System.out.println ("Receiver Error" +e); } } }
7 blocking Queues
The blocking queue can be used instead of pipe flow to implement the Inlet/outlet mode (producer/consumer). JDK1.5 provides several off-the-shelf blocking queues. now look at Arrayblockingqueue's code as Follows:
Here is a blocking queue
blockingqueue<object> blockingq = new Arrayblockingqueue<object> 10;
A thread is taken from the Queue.
For (;;) { Object o = Blockingq.take ();//queue is empty, wait (block)}
Another thread to the queue
For (;;) { blockingq.put (new Object ());//queue full, wait (block)}
As can be seen, blocking queues are easier to use than Pipelines.
8 using executors, Executor, executorservice, threadpoolexecutor
You can use thread management tasks. You can also use a set of classes provided by jdk1.5 to manage tasks more easily. From these classes we can understand a task-oriented way of thinking. These classes are:
- Executor Interface. How to Use:
Executor Executor = anexecutor;//generates a Executor instance. Executor.execute (new RunnableTask1 ());
Intent: the user is focused on task execution without worrying about the creation of tasks, and the implementation details of these third-party stakeholders ' concerns. In other words, the execution of the task and the implementation of the task are Decoupled.
In fact, there is already an excellent implementation of this interface in JDK1.5. It's Enough.
- Executors is a factory class or tool class like collections, which is used to generate instances of various Interfaces.
- The
- Executorservice interface inherits from Executor. Executor just throw the task into the executor () to carry out, the rest of the Matter. And Executorservice is different, it will do a little more control Work. For example:
class NetworkService {private final ServerSocket serversocket; Private Final Executorservice pool; Public NetworkService (int port, int Poolsize) throws IOException {serversocket = new ServerSocket (port); Pool = Executors.newfixedthreadpool (poolsize); } public void serve () {try {for (;;) {pool.execute (new Handler (serversocket.accept ())); }} catch (ioexception Ex) {pool.shutdown ();//do not perform new Tasks}}}class Handler implements Runnable {private Final Socket socket; Handler (socket Socket) {this.socket = socket;} public void run () {//read and service request}}
Executorservice (that is, The Pool object in the Code) after executing shutdown, it can no longer perform new tasks. , but the old task will continue to execute, and the tasks awaiting execution are no longer waiting.
- Task submitter communicates with performer
public static void main (String Args[]) throws Exception { Executorservice executor = Executors.newsinglethreadexecutor (); callable<string> task = new callable<string> () {public String call () throws exception{ return "test "; } }; future<string> f = executor.submit (task); String result = F.get ();//wait (block) to return the result System.out.println (result); Executor.shutdown (); }
The executor instance obtained by Executors.newsinglethreadexecutor () has the following characteristics:
- Task Order Execution. Like what:
Executor.submit (task1); Executor.submit (task2);
Must wait until the Task1 executes, the Task2 can carry Out.
- Task1 and Task2 are placed in a queue, which is handled by a worker Thread. That is: a total of 2 threads (the main thread, The worker thread that handles the task).
- For other classes, refer to the Java DOC
9 Concurrent Process Control
This section of the example comes from a Java concurrency tutorial that is less warm and may change. Salute to the low temperature.
- Countdownlatch Door Latch counter
- The
- starts the thread, and then waits for the thread to End. That is, the usual main thread, and so on, all the sub-threads are executed after the End.
public static void main (string[] Args) throws Exception {//TODO auto-generated method Stub final int count=10; Final Countdownlatch completelatch = new Countdownlatch (count);//defines The number of door latches is the sum of (int i=0;i<count;i+ +) {thread thread = new thread ("worker Thread" +i) {public void run () {//do xxxx Completelatch.countdown ();//reduce a door latch}}; Thread.Start (); } completelatch.await ();//if the door latch has not been lost, wait. }
JDK1.4, The common approach is to set the state for the child thread, and the main thread loop Detection. Ease of use and efficiency are not good.
- start many threads, wait for notification to start
public static void main (string[] Args) throws Exception {//TODO A uto-generated method Stub final Countdownlatch startlatch = new Countdownlatch (1);//defines a door latch for (int i = 0; i < 10; I++) {thread thread = new Thread ("worker Thread" + i) {public void run () {try {startlatch.await ();//if The latch is not finished yet wait} catch (interruptedexception E) { }//do xxxx}}; Thread.Start (); } Startlatch.countdown ();//reduce a door latch}
- cyclibarrier. Wait until all threads have reached a starting line before they can begin to Run.
public class Cyclibarriertest implements Runnable {private Cyclicbarrier barrier; Public cyclibarriertest (cyclicbarrier Barrier) {this.barrier = barrier; } public void run () {//do xxxx; Try {this.barrier.await ();//thread runs this checks to see if the other threads are all aligned, and waits until the alignment is Reached. To execute the contents of the Run function body of barrier} catch (Exception e) {}}/** * @param args */public static voi D main (string[] Args) {//parameter 2 means that two threads have reached the starting line to proceed with the execution of cyclicbarrier barrier = new Cyclicbarrier (2, new Runnab Le () {public void run () {//do xxxx; } }); thread T1 = new Thread (new cyclibarriertest (barrier)); Thread t2 = new Thread (new cyclibarriertest (barrier)); T1.start (); T2.start (); }}
This simplifies the traditional way of using counter +wait/notifyall to implement this Functionality.
10 Concurrent 3 laws
- Amdahl LAW. Given the size of the problem, the parallelization portion accounts for 12%, so even if the parallelism is applied to the extreme, the performance of the system can only be increased by 1/(1-0.12) = 1.136 times Times. That is, parallelism has an upper limit on improving system performance.
- Gustafson LAW. Gustafson law says that Amdahl's law does not consider that more computing power can be used as the CPU Increases. Its essence is to change the size of the problem so that the remaining 88% of the Amdahl law in the serial processing parallelization, so that the performance threshold can be breached. is essentially a space-changing time.
- Sun-ni LAW. is a further extension of the first two laws. The main idea is that the speed of calculation is limited by the speed of storage rather than the CPU. therefore, we should make full use of computing resources such as storage space, to maximize the problem size to produce better/more accurate Solution.
11 from concurrency to parallelism
Computer recognition of objects need to be fast calculation, so that the chip is hot, and the person in the recognition of objects at a glance, but does not cause a brain cell burned hot scorch (exaggerated) and feel uncomfortable, is because the brain is a distributed parallel operation system, Just as Google uses some inexpensive Linux servers to perform large and complex computations, countless neurons in the brain are counted alone to share the results, thus instantaneously accomplishing the effects of a single CPU trillion operation. imagine, if created in the field of parallel processing, will have an immeasurable impact on the development and future of Computers. Of course, the challenges can be imagined: many of the problems are not easy to "split" The.
How Java concurrency is handled