JAVA5 's Java.util.concurrent package introduces a large number of new classes for solving concurrency problems, and these new classes are an abstraction at a higher level, relative to the previous ones based on thread synchronization and communication, and are relatively easy to use. This blog will learn about two new classes: Countdownlatch and Cyclicbarrier, and use Cyclicbarrier to simulate a simple horse racing game.
I. Countdownlatch
When using the Countdownlatch object, we need to set an initial count value for it, and then the task of calling await () on this object will block until the count of the object is reduced to 0, and the other task can invoke the countdown () of the object when it completes its work. method to reduce the count value of this object. So this class can be used to synchronize one or more tasks, forcing them to wait for a set of operations performed by other tasks to complete; A typical scenario is to decompose a program into n separate, countdownlatch tasks and create a value of N, which, when each task is completed, The countdown () is called on this object. The task that waits for the problem to be resolved calls await () on the object, blocking itself until the object count is reduced to 0, and it is important to note that this object does not coordinate the order in which n tasks are executed. A sample framework for this technique is shown below:
PackageLKL;ImportJava.util.Random;ImportJava.util.concurrent.CountDownLatch;ImportJava.util.concurrent.ExecutorService;ImportJava.util.concurrent.Executors;ImportJava.util.concurrent.TimeUnit;/** * Countdownlatch is used to synchronize one or more tasks, forcing them to wait for a set of operations performed by another task to complete * *///Pre-executed tasksClass Taskportion implements runnable{Private Static intCounter =0;Private Final intId= counter++;//Global multiple threads share a random object, which actually involves a concurrency problem //Just actually random.next () is thread-safe in itself, so we don't need to synchronize ourselves Private StaticRandom Rand =NewRandom ( -);Private FinalCountdownlatch latch; Public taskportion(Countdownlatch latch) { This. latch = latch; } Public void Run(){Try{DoWork (); Latch.countdown ();//Decrease Count value}Catch(Interruptedexception ex) {System.out.println ( This+"Exit by interrupting exception"); } }//thread sleep for some time simulation do some work Public void DoWork()throwsinterruptedexception{TimeUnit.MILLISECONDS.sleep (Rand.nextint ( -)); System.out.println ( This+"Completed"); } PublicStringtoString(){returnString.Format ("%1$-3d", id); }}class Waitingtask implements runnable{Private Static intCounter =0;Private FinalCountdownlatch latch;Private Final intid = counter++; Public Waitingtask(Countdownlatch latch) { This. latch = latch; } Public void Run() {Try{latch.await ();;//Before the count on latch is reduced to 0, it will be blocked hereSystem.out.println ( This+"Completed"); }Catch(Interruptedexception ex) {System.out.println (); } } PublicStringtoString(){returnString.Format ("Watitingtask%1$-3d", id); }} Public class countdownlatchdemo { Static Final intSIZE = -; Public Static void Main(string[] args)throwsexception{Executorservice exec = Executors.newcachedthreadpool ();//All threads must share a latch object //Set the initial count value to 100, that is, you must wait for 100 tasks to complete //The task of calling await () on this object to executeCountdownlatch latch =NewCountdownlatch (SIZE);//Open 10 waiting Threads for(intI=0; i<Ten; i++) {Exec.execute (NewWaitingtask (latch)); }//Open 100 pre-executed threads for(intI=0; i<size; i++) {Exec.execute (NewTaskportion (latch)); } System.out.println ("latched all TAKSS"); Exec.shutdown (); }}
Two. Cyclicbarrier
Cyclicbarrier applies to this situation: we want to create a set of tasks that are executed in parallel, and then wait until the next step, until all the tasks are completed (which is not possible by normal thread scheduling). It allows all tasks to be lined up at the fence so that they can move forward in a consistent way. This looks similar to the above Countdownlatch, but Countdownlatch can only trigger one event, and Cyclicbarrier is reusable multiple times. More specific uses can be described as follows: we create a Cyclicbarrier object that specifies an initial count of N and Runnable object R, and then submits it to n threads, each of which invokes an await () on the object after the current task is completed. Decrease the count value and the current thread will block, so that until the last thread calls await (), the count is reduced to 0, then the run () method of R on the Cyclibarrier object is called, and after the run () method executes, It resets the count value of the Cyclicbarrier object and then repeats the above procedure. Through such a process, the effect of making multiple threads move consistently forward is achieved.
Here's a horse racing game by using this kind of simulation:
PackageLKL;ImportJava.util.ArrayList;ImportJava.util.List;ImportJava.util.Random;ImportJava.util.concurrent.BrokenBarrierException;ImportJava.util.concurrent.CyclicBarrier;ImportJava.util.concurrent.ExecutorService;ImportJava.util.concurrent.Executors;ImportJava.util.concurrent.TimeUnit;/** * Simulated horse racing game * The following program uses "*" to indicate the current location of the horse, using "= =" to represent the fence * The concrete idea is that we use a thread to simulate a horse, in which we generate a random number each time to indicate how many steps this horse has run And then use Cyclicbarrier to synchronize multiple threads * so that they can move forward consistently, resulting in a horse racing effect. We will print out what happens after each move in the run () method of Cycylicbarrier. * You can see the effect of this simulation by adjusting the size of the console to only the horse. * *///Simulate a horse's threadClass Horse implements runnable{Private Static intCounter =1;Private Final intid = counter++;//Horse's number Private intstrides =0;//Number of steps currently taken by the horse Private StaticRandom Rand =NewRandom ( -);Private StaticCyclicbarrier barrier;//All threads share a Cyclicbarrier object Public Horse(Cyclicbarrier b) {barrier = b; }//Returns the number of steps the current horse has run Public synchronized int Getstrides(){returnstrides; } Public void Run(){Try{ while(! Thread.interrupted ()) {synchronized( This){//How many steps this moveStrides+=rand.nextint (3);//0,1,2}//block until the last thread also calls this method ///Then executes the barrier run () task, then resets the count value to unblock the thread and then calls these threads //This will ensure that each thread is dispatched every time, and then output the current situation //And then make the next round of calls so you can simulate the race situation. Otherwise, because the operating system thread //The call is uneven and is not simulated. Barrier.await (); } }Catch(Interruptedexception ex) {System.out.println ( This+"Exit by interrupting exception"); }Catch(Brokenbarrierexception e) {exceptions caused by//await () Throw NewRuntimeException (); } } PublicStringtoString(){return "Horse"+id+" "; }//Use "*" to indicate the current horse's trajectory PublicStringTracks() {StringBuilder s =NewStringBuilder (); for(intI=0; I<getstrides (); i++) {S.append ("*"); } s.append (ID);returnS.tostring (); }} Public class horserace { Static Final intFinish_line= the;//finish line steps PrivatelistNewArraylistPrivateExecutorservice exec = Executors.newcachedthreadpool ();PrivateCyclicbarrier barrier; Public horserace(intNhorse,Final intPause) {//Construct a Cyclicbarrier object when you need to pass in a Runnable object when the count value is reduced to 0 //Execute, which is passed in the form of an anonymous inner class. Here this Runnable object is responsible for printing //out of the situation when all horses are moved once each time. Barrier =NewCyclicbarrier (Nhorse,NewRunnable () { Public void Run() {StringBuilder s =NewStringBuilder ();//Show Fence for(intI=0; i<finish_line; i++) {S.append ("="); } System.out.println (s);//Print the current position of each horse ("*" +id indicated) for(Horse horse:horses) {System.out.println (Horse.tracks ()); }//If the horse crosses the finish line, print out the horse wins //And end the game (end all race threads) for(Horse horse:horses) {if(Horse.getstrides () >=finish_line) {System.out.println (horse+"won"); Exec.shutdownnow ();return; } }Try{//Sleep for some timeTimeUnit.MILLISECONDS.sleep (pause); }Catch(Interruptedexception ex) {Ex.printstacktrace (); } } });//produce nhorse horse race for(intI=0; i<nhorse;i++) {Horse Horse =NewHorse (barrier); Horses.add (horse); Exec.execute (horse); } } Public Static void Main(string[] args) {//Default 7 horse races intNhorses =7;intPause = $;NewHorserace (Nhorses,pause); }}
Thinking in Java---concurrent new component learning + horse racing game simulation