Recently, the Java concurrent programming combat-java consurrency in practice has been reviewed, and some of the common tools mentioned in the book are recorded here:
I. Latching (door bolt)-Countdownlatch
Scenario: multithreaded testing, usually in order to accurately timing, requires all the threads ready to start execution, to prevent the cable enters upgradeable starting, resulting in unfair, similar when all threads are executed, the entire program is run complete.
/** * Lockout test (Yang over http://yjmyzz.cnblogs.com/under the Bodhi tree) * * @throws interruptedexception * * @Test Public void Countdownlatch () throws interruptedexception {Countdownlatch Startlatch = new Countdownlatch (1);//Similar starting pistol Countdownlatch Endlatch = new Countdownlatch (10);//The number here is the same as the number of threads for (int i = 0; i <; i++) {Th Read T = new Thread ((), {try {startlatch.await ();///wait until the starting gun is ringing to prevent cable enters upgradeable run System.out.println (Thread.CurrentThread (). GetName () + "is running ..."); Thread.Sleep (10); } catch (Interruptedexception e) {thread.currentthread (). interrupt (); } finally {Endlatch.countdown ();//per thread after execution completes, Count}}); T.setname ("Thread-" + i); T.start (); } Long start = System.currenttimemillis (); Startlatch.countdown ();//pistol, all Threads "Run" EndlatCh.await ();//wait for all threads to complete long end = System.currenttimemillis (); System.out.println ("done! EXEC time = "+ (End-start) +" MS "); }
Execution Result:
Thread-1 is running ...
Thread-5 is running ...
Thread-8 is running ...
Thread-4 is running ...
Thread-3 is running ...
Thread-0 is running ...
Thread-2 is running ...
Thread-9 is running ...
Thread-7 is running ...
Thread-6 is running ...
done! EXEC time = ms
Note: You can comment out the 14th line, and then see how the results of the operation are different.
Second, signal volume (Semaphore)
Scenario: Concurrent access scenarios where the number of resources is limited.
public class Boundedhashset<t> {private final set<t> Set; Private final Semaphore Semaphore; public boundedhashset (int bound) {This.set = Collections.synchronizedset (New hashset<t> ()); This.semaphore = new semaphore (bound); } public boolean Add (T T) throws interruptedexception {if (!semaphore.tryacquire (5, Timeunit.seconds)) {return false; } ; Boolean added = false; try {added = Set.add (t); return added; } finally {if (!added) {semaphore.release (); }}} public boolean remove (Object o) {Boolean removed = Set.remove (o); if (removed) {semaphore.release (); } return removed; }} @Test public void Semaphoretest () throws Interruptedexception {boundedhashset<string> set = new boundedhashset<> (5); for (int i = 0; i < 6; i++) {if (Set.add (i + "")) {System.out.println (i + "added!"); } else {System.out.println (i + "not add to set!"); } } }
The example above turns a normal set into a bounded container. The results of the implementation are as follows:
0 Added!
1 Added!
2 Added!
3 Added!
4 Added!
5 Not add to set!
Third, fence Cyclicbarrier
This is similar to latching, you can set a "barrier" point through the code, the other threads arrive at that point to continue, often used to constrain other threads to reach a certain state, it is allowed to do later.
public class Worker extends Thread {private Cyclicbarrier cyclicbarrier; Public Worker (Cyclicbarrier cyclicbarrier) {this.cyclicbarrier = Cyclicbarrier; } private void Step1 () {System.out.println (This.getname () + "Step 1 ..."); } private void Step2 () {System.out.println (This.getname () + "Step 2 ..."); } public void Run () {Step1 (); try {cyclicbarrier.await (); } catch (Interruptedexception e) {e.printstacktrace (); } catch (Brokenbarrierexception e) {e.printstacktrace (); } step2 (); }} @Test public void Cyclicbarriertest () throws Interruptedexception, brokenbarrierexception {Cyclicbarr Ier cyclicbarrier = new Cyclicbarrier (11); for (int i = 0; i < i++) {worker w = new Worker (Cyclicbarrier); W.start (); } CYClicbarrier.await (); }
Here we assume that there is a worder thread that has a 2-step operation that requires all threads to complete step1 before they can continue step2. The results of the implementation are as follows:
Thread-0 Step 1 ...
Thread-1 Step 1 ...
Thread-2 Step 1 ...
Thread-3 Step 1 ...
Thread-4 Step 1 ...
Thread-5 Step 1 ...
Thread-6 Step 1 ...
Thread-7 Step 1 ...
Thread-8 Step 1 ...
Thread-9 Step 1 ...
Thread-9 Step 2 ...
Thread-0 Step 2 ...
Thread-3 Step 2 ...
Thread-4 Step 2 ...
Thread-6 Step 2 ...
Thread-2 Step 2 ...
Thread-1 Step 2 ...
Thread-8 Step 2 ...
Thread-7 Step 2 ...
Thread-5 Step 2 ...
Iv. Exchanger
If 2 threads need to exchange data, exchanger can be useful, see the following example:
@Test public void Exchangertest () { exchanger<string> Exchanger = new exchanger<> (); thread T1 = new Thread ((), { String temp = "aaaaaa"; SYSTEM.OUT.PRINTLN ("Thread 1 before Exchange:" + temp); try { temp = exchanger.exchange (temp); } catch (Interruptedexception e) { e.printstacktrace (); } SYSTEM.OUT.PRINTLN ("Thread 1 Exchange:" + temp); }); Thread t2 = new Thread ((), { String temp = "BBBBBB"; SYSTEM.OUT.PRINTLN ("Thread 2 before Exchange:" + temp); try { temp = exchanger.exchange (temp); } catch (Interruptedexception e) { e.printstacktrace (); } System.out.println ("Thread 2 Exchange:" + temp); }); T1.start (); T2.start (); }
Execution Result:
Thread 1 before swapping: aaaaaa
Thread 2 before swapping: BBBBBB
Thread 2 after Exchange: AAAAAA
Thread 1 after Exchange: BBBBBB
Wu, Futuretask/future
Some very time-consuming operations that can be converted into asynchronous with the future, without blocking the subsequent processing until the result is really needed to call get get results
@Test public void Futuretasktest () throws Executionexception, Interruptedexception, timeoutexception { Callable<string> callable = () { System.out.println ("very time-consuming operation processing ... "); Thread.Sleep (the); return "Done"; }; futuretask<string> futuretask = new futuretask<> (callable); System.out.println ("Ready ... "); New Thread (Futuretask). Start (); System.out.println ("Main thread other processing ... "); System.out.println (Futuretask.get ()); SYSTEM.OUT.PRINTLN ("Processing done! "); System.out.println ("-----------------"); SYSTEM.OUT.PRINTLN ("Executor ready ... "); Executorservice Executorservice = Executors.newsinglethreadexecutor (); future<string> future = Executorservice.submit (callable); System.out.println (Future.get (Ten, Timeunit.seconds)); }
Execution Result:
Ready...
Main thread Other processing ...
Very time-consuming operation in the process ...
Done
Processing done!
-----------------
Executor ready ...
Very time-consuming operation in the process ...
Done
Six, blocking queue Blockingqueue
Blocking queues can implement producer-consumer patterns between threads. For example: Thread producer simulates fast production data, while thread consumer simulates slow consumption data, and when the upper limit of the queue is reached (that is, the data generated by the producer has not been placed), the queue is blocked.
@Test public void Blockingqueuetest () throws interruptedexception {final blockingqueue<string> Blockingde que = new arrayblockingqueue<> (5); Thread producer = new Thread () {public void run () {Random rnd = new Random (); while (true) {try {int i = Rnd.nextint (10000); Blockingdeque.put (i + ""); System.out.println (This.getname () + "produces a number:" + i); Thread.Sleep (Rnd.nextint (50));//simulation producer Quick Production} catch (Interruptedexception e) {Thr Ead.currentthread (). interrupt (); } } } }; Producer.setname ("producer 1"); Thread consumer = new Thread () {public void run () {while (true) {Random rn D = new Random (); try {String i = BlockinGdeque.take (); System.out.println (This.getname () + "consumes a number:" + i); Thread.Sleep (Rnd.nextint (10000));//consumer analog Slow consumption} catch (Interruptedexception e) { Thread.CurrentThread (). interrupt (); } } } }; Consumer.setname ("Consumer 1"); Producer.start (); Consumer.start (); while (true) {thread.sleep (100); } }
Execution Result:
Producer 1 produces a number: 6773
Consumer 1 consumed a number: 6773
Producer 1 produces a number: 4456
Producer 1 produces a number: 8572
Producer 1 produces a number: 5764
Producer 1 produces a number: 2874
Producer 1 produces a number: 780 # Note This is blocked until a consumer consumes a piece of data to continue production
Consumer 1 consumed a number: 4456
Producer 1 produces a number: 4193
Examples of some common concurrency tools in Java