Jdk6 RC has been released recently, but it is too late to use the new features of jdk5. Although it has not been used yet in the project, you can write some demos to experience the charm of tiger, the present era is the era of experience. Everything must be done in person to have a say. How can we feel that Chairman Mao is "seeking truth from facts.
One of the highlights of JDK 5 is to introduce Doug Lea's concurrent Library to the java standard library. Doug Lea is indeed a cool man, can teach, can publish books, can code, but this is still quite common abroad, and domestic professors are too far apart.
Generally, servers require thread pools, such as web servers and FTP servers. However, they generally implement thread pools themselves, such as Tomcat, resin, and jetty previously introduced, now with JDK 5, there is no need to repeat the wheel and use it directly. Besides, it is very convenient to use and has high performance.
package concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestThreadPool { public static void main(String args[]) throws InterruptedException { // only two threads ExecutorService exec = Executors.newFixedThreadPool(2); for(int index = 0; index < 100; index++) { Runnable run = new Runnable() { public void run() { long time = (long) (Math.random() * 1000); System.out.println("Sleeping " + time + "ms"); try { Thread.sleep(time); } catch (InterruptedException e) { } } }; exec.execute(run); } // must shutdown exec.shutdown(); } } |
The preceding example uses two thread pools to process 100 threads. But there is a problem: During the for loop process, the main thread will be blocked because the thread pool has Idle threads. To solve this problem, we generally start a thread for the for loop to avoid the main thread blocking caused by the full thread pool. But I didn't handle it here. [Important correction: after testing, the thread pool will not be blocked even if the thread pool size is smaller than the actual number of threads, which is different from the Tomcat thread pool, it places the runnable instance in an "infinite" blockingqueue, so it does not need a thread to start the for loop. Doug Lea is amazing]
In addition, it uses the static function of executors to generate a fixed thread pool. As the name suggests, the thread in the thread pool will not be released, even if it is an idle. This will cause performance problems. For example, if the thread pool size is 200, after all the threads are used up, all the threads will remain in the pool, the corresponding memory and thread switching (while (true) + sleep loop) will increase. To avoid this problem, you must use threadpoolexecutor () to construct it directly. You can set "Maximum number of Threads", "minimum number of Threads", and "keepalive time of Idle threads" like Tomcat's thread pool ". Through these solutions, we can basically Replace the Tomcat thread pool implementation scheme.
Note that the thread pool must be closed explicitly using shutdown. Otherwise, the main thread cannot exit. Shutdown does not block the main thread.
Many long-running applications sometimes need to run tasks on a regular basis to complete some work such as statistics and optimization. For example, when processing user tickets in the telecom industry, they need to process tickets every other minute; the website collects statistics on user traffic and number of users every early morning. It collects statistics on the sales volume of the day and the best-selling products at a.m.. It backs up databases every Sunday. The Company calculates the salary and transfers funds on the 10th of each month, these are scheduled tasks. With the java concurrent database concurrent, you can easily complete these tasks, which is very simple.
PackageConcurrent; Import staticJava. util. concurrent. TimeUnit. SECONDS; ImportJava. util. Date; ImportJava. util. concurrent. Executors; ImportJava. util. concurrent. ScheduledExecutorService; ImportJava. util. concurrent. ScheduledFuture; Public classTestScheduledThread { Public staticVoidMain (String [] args ){ FinalScheduledExecutorService schedors = Executors . NewScheduledThreadPool (2 ); FinalRunnable beeper =NewRunnable (){ IntCount = 0; PublicVoidRun (){ System. out. println (NewDate () + "beep" + (++ count )); } }; // Run every two seconds after 1 second FinalScheduledFuture <?> BeeperHandle = schedrate. scheduleAtFixedRate ( Beeper, 1, 2, SECONDS ); // Run the task in 2 seconds, and run the task again in 5 seconds after the task is run. FinalScheduledFuture <?> BeeperHandle2 = scheduler . ScheduleWithFixedDelay (beeper, 2, 5, SECONDS ); // Close the task 30 seconds later and close Scheduler Schedle. schedule (NewRunnable (){ PublicVoidRun (){ BeeperHandle. cancel (True); BeeperHandle2.cancel (True); Scheddown. shutdown (); } }, 30, SECONDS ); } } |
In order to exit the process, the above Code adds the operation to disable Scheduler. For applications that run within 24 hours, there is no need to disable Scheduler.
In practical applications, sometimes multiple threads need to work at the same time to accomplish the same thing, and in the process of completion, they often wait for other threads to finish a certain stage before execution, after All threads reach a certain stage, they are executed in a unified manner.
For example, several tour groups need to arrive in Wuhan through Shenzhen, Guangzhou, Shaoguan, and Changsha. There are self-driving tours, hiking tours, and bus tours in the tour group. These tour groups depart at the same time, and every destination must wait for other tour groups to arrive here and start at the same time, till they all arrive at the terminal station Wuhan.
At this time, CyclicBarrier can be used. The most important attribute of javasicbarrier is the number of participants, and the most important method is await (). When await () is called by all threads, it indicates that these threads can continue to run; otherwise, they will wait.
PackageConcurrent; ImportJava. text. SimpleDateFormat; ImportJava. util. Date; ImportJava. util. concurrent. BrokenBarrierException; ImportJava. util. concurrent. javasicbarrier; ImportJava. util. concurrent. ExecutorService; ImportJava. util. concurrent. Executors; Public classTestCyclicBarrier { // Time required for walking: Shenzhen, Guangzhou, Shaoguan, Changsha, and Wuhan Private staticInt[] TimeWalk = {5, 8, 15, 15, 10 }; // Self-driving tour Private staticInt[] TimeSelf = {1, 3, 4, 4, 5 }; // Coach Private staticInt[] TimeBus = {2, 4, 6, 6, 7 };
StaticString now (){ SimpleDateFormat sdf =NewSimpleDateFormat ("HH: mm: ss "); ReturnSdf. format (NewDate () + ":"; }Static classTourImplementsRunnable { PrivateInt[] Times; PrivateCyclicBarrier barrier; PrivateString tourName; PublicTour (CyclicBarrier barrier, String tourName,Int[] Times ){ This. Times = times; This. TourName = tourName; This. Barrier = barrier; } PublicVoidRun (){ Try{ Thread. sleep (times [0] * 1000 ); System. out. println (now () + tourName + "Reached Shenzhen "); Barrier. await (); Thread. Sleep (Times [1] * 1000 ); System. Out. println (now () + tourname + "reached Guangzhou "); Barrier. Await (); Thread. Sleep (Times [2] * 1000 ); System. Out. println (now () + tourname + "reached Shaoguan "); Barrier. Await (); Thread. Sleep (Times [2] * 1000 ); System. Out. println (now () + tourname + "reached Changsha "); Barrier. await (); Thread. sleep (times [4] * 1000 ); System. out. println (now () + tourName + "Reached Wuhan "); Barrier. await (); }Catch(InterruptedException e ){ }Catch(BrokenBarrierException e ){ } } } Public staticVoidMain (String [] args ){ // Three tour groups Required icbarrier barrier =NewCyclicBarrier (3 ); ExecutorService exec = Executors. newFixedThreadPool (3 ); Exec. submit (NewTour (barrier, "hour Tour", timeWalk )); Exec. submit (NewTour (barrier, "SelfTour", timeSelf )); Exec. submit (NewTour (barrier, "BusTour", timeBus )); Exec. shutdown (); } }
|
Running result:
00: 02: 25: SelfTour Reached Shenzhen
00: 02: 25: BusTour Reached Shenzhen
00: 02: 27: Drawing tour Reached Shenzhen
00: 02: 30: SelfTour Reached Guangzhou
00: 02: 31: BusTour Reached Guangzhou
00: 02: 35: Drawing tour Reached Guangzhou
00: 02: 39: SelfTour Reached Shaoguan
00: 02: 41: BusTour Reached Shaoguan
BlockingQueue in the concurrent library is a fun class. As its name suggests, BlockingQueue is a blocking queue. This class mainly provides two methods: put () and take (). The former puts an object in the queue. If the queue is full, wait until there are idle nodes; the latter retrieves an object from the head. If there is no object, it waits until there is a desirable object.
The following example is simple. A read thread is used to add the file objects to be processed to the blocking queue. The other four write threads are used to retrieve file objects. to simulate the long write operation time, this feature allows a thread to sleep for a random length. In addition, this Demo also uses the thread pool and atomic INTEGER (AtomicInteger). AtomicInteger can achieve atomic update under concurrent conditions, avoiding the use of synchronized and high performance. The put and take operations in the blocked queue will be blocked. In order to exit the thread, a "tag" is added to the queue, which is also called "Sentinel" in the algorithm ", when this sentry is found, the write thread exits.
Of course, the thread pool also needs to exit explicitly.
package concurrent;
import java.io.File;
import java.io.FileFilter;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class TestBlockingQueue {
static long randomTime() {
return (long) (Math.random() * 1000);
}
Public staticVoidMain (string [] ARGs ){
// Can contain 100 files
FinalBlockingqueue <File> queue =NewLinkedblockingqueue <File> (100 );
// Thread Pool
FinalExecutorservice exec = executors. newfixedthreadpool (5 );
FinalFile root =NewFile ("F: // javalib ");
// Completion mark
FinalFile exitfile =NewFile ("");
// Read count
FinalAtomicinteger rc =NewAtomicinteger ();
// Number of writes
FinalAtomicinteger WC =NewAtomicinteger ();
// Read thread
Runnable READ =NewRunnable (){
PublicVoidRun (){
Scanfile (Root );
Scanfile (exitfile );
}
PublicVoidScanfile (File file ){
If(File. isdirectory ()){
File [] files = file. listfiles (NewFilefilter (){
PublicBooleanAccept (File pathname ){
ReturnPathname. isdirectory ()
| Pathname. getpath (). endswith (". Java ");
}
});
For(File one: files)
Scanfile (one );
}Else{
Try{
IntIndex = RC. incrementandget ();
System. Out. println ("read0:" + index + ""
+ File. getpath ());
Queue. Put (File );
}Catch(Interruptedexception e ){
}
}
}
};
Exec. Submit (read );
// Four write threads
For(IntIndex = 0; index <4; index ++ ){
// Write thread
FinalIntNO = index;
Runnable write =NewRunnable (){
String threadName = "Write" + NO;
PublicVoidRun (){
While(True){
Try{
Thread. sleep (randomTime ());
IntIndex = wc. incrementAndGet ();
File file = queue. take ();
// No object exists in the queue
If(File = exitFile ){
// Add the "flag" again to make other threads exit normally
Queue. put (exitFile );
Break;
}
System. Out. println (threadname + ":" + index + ""
+ File. getpath ());
}Catch(Interruptedexception e ){
}
}
}
};
Exec. Submit (write );
}
Exec. Shutdown ();
}
}
From the name, we can see that CountDownLatch is a countdown lock. When the countdown reaches 0, the event is triggered, that is, unlocking, and other people can enter. In some application scenarios, you need to wait for a condition to meet the requirements before doing the following. At the same time, when the thread is complete, the event is triggered for subsequent operations.
CountDownLatch the most important methods are countDown () and await (). The former is mainly the reciprocal, and the latter is waiting for the reciprocal to 0. If it does not reach 0, it will only wait for blocking.
A CountDouwnLatch instance cannot be used repeatedly, that is, it is a one-time lock and cannot be closed once it is opened. To use it again, consider using javasicbarrier.
The example below briefly describes how to use CountDownLatch to simulate a 100-meter race. ten contestants are ready, and only wait for the referee to give an order. When everyone reaches the finish point, the game is over.
Similarly, the thread pool needs to be explicitly shutdown.
package concurrent;import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; Public classTestCountDownLatch { Public staticVoidMain (String [] args)ThrowsInterruptedException { // Start the reciprocal lock FinalCountDownLatch begin =NewCountDownLatch (1 ); // The ending reciprocal lock FinalCountdownlatch end =NewCountdownlatch (10 ); // Ten contestants FinalExecutorservice exec = executors. newfixedthreadpool (10 ); For(IntIndex = 0; index <10; index ++ ){ FinalIntNo = index + 1; Runnable run =NewRunnable (){ PublicVoidRun (){ Try{ Begin. Await (); Thread. Sleep ((Long) (Math. Random () * 10000 )); System. Out. println ("no." + NO + "arrived "); }Catch(Interruptedexception e ){ }Finally{ End. Countdown (); } } }; Exec. submit (run ); } System. out. println ("Game Start "); Begin. countDown (); End. await (); System. out. println ("Game Over "); Exec. shutdown (); } }
|
Running result:
Game Start
No. 4 arrived
No.1 arrived
No. 7 arrived
No. 9 arrived
No. 3 arrived
No. 2 arrived
No. 8 arrived
No. 10 arrived
No. 6 arrived
No. 5 arrived
Game Over
Sometimes in practical applications, some operations are time-consuming, but not an indispensable step. For example, when you use a web browser to browse news, the most important thing is to display text content. As for the picture that matches news, it is not so important. Therefore, first ensure that the text information is displayed first, the image information will be displayed after the meeting, but cannot be displayed. Since the image download is a time-consuming operation, you must download it from the beginning.
The Future class of the Java concurrent library can meet this requirement. Important methods of Future include get () and cancel (), get () to obtain data objects. If the data is not loaded, blocking will occur until the data is obtained, while cancel () cancel data loading. Another get (timeout) operation means that if no result is obtained within the timeout time, the system will fail to return, instead of blocking.
The Demo below briefly describes how to use Future: a very time-consuming operation must be started at the beginning, but cannot wait all the time; other important tasks must be done, you can do things that are not important.
package concurrent;import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; Public classTestFutureTask { Public staticVoidMain (String [] args)ThrowsInterruptedException, ExecutionException { FinalExecutorService exec = Executors. newFixedThreadPool (5 ); Callable <String> call =NewCallable <String> (){ PublicString call ()ThrowsException { Thread. Sleep (1000*5 ); Return"Other less important but longtime things ."; } }; Future <string> task = exec. Submit (CALL ); // Important Thread. Sleep (1000*3 ); System. Out. println ("let's do important things ."); // Other unimportant things String OBJ = task. Get (); System. out. println (obj ); // Close the thread pool Exec. shutdown (); } }
|
Running result:
Let's do important things.
Other less important but longtime things.
Consider the following scenarios: When browsing a webpage, the browser downloads the image files from the webpage using five threads. Due to the influence of image size, website access speed, and many other factors, the download time varies greatly. If the image is downloaded first, it is first displayed on the interface. Otherwise, the downloaded image is displayed later.
Java's concurrent library completionservice can meet the requirements of this scenario. This interface has two important methods: Submit () and take (). The submit is used to submit a runnable or callable object, which is generally submitted to a thread pool for processing. The take object is the future object of the runnable or callable instance that has been executed. If not, wait. Completionservice also has a corresponding method poll, which is similar to take, but does not wait. If the requirement is not met, a null object is returned.
package concurrent;import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class TestCompletionService { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService exec = Executors.newFixedThreadPool(10); CompletionService<String> serv = new ExecutorCompletionService<String>(exec); for (int index = 0; index < 5; index++) { final int NO = index; Callable<String> downImg = new Callable<String>() { public String call() throws Exception { Thread.sleep((long) (Math.random() * 10000)); return "Downloaded Image " + NO; } }; serv.submit(downImg);
|