I have written two articles on JDBC source code. I think it is a bit boring. I have inserted a juc series of articles to change my appetite. I have mentioned some articles about J u C, the juc system contains a lot of content, not a sentence or two. I will first list the juc-related content that will be listed, and then introduce the version of this article: Tools
The main sections of the J. u. C system contain content, as shown in:
Note that each part of the package contains many classes and processors, and contains, references, and implements each other.
Speaking of j uc, Java multithreading and locks, we have mentioned some state conversion and interruptions. Today we will use its tools to implement some trivial things, when talking about other content, let's look at how this tool is implemented.
Tools is the focus of this Article. What are the main features of tools:
Tools also contains five parts of knowledge:Executors,Semaphor,Exchanger,Cyclicbarrier,Countdownlatch,In fact, there are five tool categories. These five tool categories are useful for the future.
Executors:
In fact, it is mainly used to create a thread pool and acts as a proxy for the creation of a thread pool, making it easy to create entry parameters, by using the method name, you will know what kind of thread pool you want to create and what kind of functions are. In fact, the thread pool is implemented in a unified way and is reloaded by the constructor, different functions are implemented. However, this method often does not know the meaning of the changes to the specific entry parameters unless the source code is read. At this time, the builder mode is implemented, builder can tell you what it is.
Common methods are ):
1. Create a thread pool of the specified size. If the size is exceeded, put it into the blocken queue. The default value is queue blockingqueue. The default threadfactory is executors. defaultthreadfactory () is an internal class of executors.
Executors. newfixedthreadpool (INT)
Internal implementation:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
2. Create a thread pool of the specified size. If the size is exceeded, put it into the blocken queue. The default value is linkedblockingqueue. Specify threadfactory by yourself and write threadfactory by yourself,Must be implements threadfactory, implementation method: newthread (runnable).
Executors. newfixedthreadpool (INT, threadfactory)
Internal implementation:
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }
3. Create a thread pool with a length of 1, that is, there is only one thread pool with a length. The redundant thread pool must wait. It is the same as the result obtained by calling executors. newfixedthreadpool (1:
Executors. newsinglethreadexecutor ()
Internal implementation:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
Is it quite simple, that is, changing parameters, you can also new it yourself.
4. Similar to method 3, you can customize threadfactory. I will not talk about it here!
5. Create a thread pool that can be cached. By default, the thread pool is cached for 60 s. The data is stored in a synchronousqueue instead of the blocken queue. That is, the thread enters scheduling as long as a thread comes in, this is not recommended because it is prone to problems unless it is used to simulate some concurrent tests:
Executors. newcachedthreadpool ();
Internal implementation:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
6. Add a custom threadfactory, similar to Method 5.
7. Add the thread pool of a Schedule scheduler. By default, there is only one Scheduler:
Executors. newsinglethreadscheduledexecutor ();
Internal implementation is (here we can see that threadpoolexector is not used, schedule has changed to a class, internal implementation through the internal class in the scheduledthreadpoolexecutor class)ScheduledfuturetaskThis internal class isPrivateBy default, it cannot be referenced ):
public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1)); }
8. add your own threadfactory, just like 7.
9. Add a schedule thread pool scheduler, andNewfixedthreadpoolA bit similar:
Executors. newscheduledthreadpool ();
Internal code:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }
In fact, there are some other methods in the internal exectors, which we will not describe much about. In addition, we can first understand that exectors are actually a tool class and provide a series of static methods, to create the corresponding thread pool visually, so you don't need to think it's amazing. What's amazing is how internal implementation is achieved. This article will not elaborate on the implementation of various thread pools in the article, I just got to know each other.ExectorWe will describe these details in detail during the series.
OK. Let's continue to the next topic:
Semaphor. What about this bird?
A: We can see from the name that it is a semaphore.
What can semaphores do?
A: perform access control based on some thresholds.
Okay. Here we simulate how to control the access speed when multiple threads are concurrent with a piece of code:
Import Java. util. random; import Java. util. concurrent. semaphore; public class semaphoretest {private final static semaphore max_sema_phore = new semaphore (10); public static void main (string [] ARGs) {for (INT I = 0; I <100; I ++) {final int num = I; final random Radom = new random (); New thread () {public void run () {Boolean acquired = false; try {max_sema_phore.acquire (); acquired = true; syst Em. Out. println ("I Am a thread:" + num + "I got the right to use! "+ Datetimeutil. getdatetime (); long time = 1000 * Math. max (1, math. ABS (Radom. nextint () % 10); thread. sleep (time); system. out. println ("I Am a thread:" + num + "I have finished running! "+ Datetimeutil. getdatetime ();} catch (exception e) {e. printstacktrace () ;}finally {If (acquired) {max_sema_phore.release ();}}}}. start ();}}}
Here is a simple simulation of concurrent 100 threads to access a program, at this time to control up to 10 running at the same time, with this semaphore, the running program uses a thread to sleep at a random time. You can see that some threads later say they have been released, and some threads have been acquired. If they are not released, they cannot be obtained, in terms of internal implementation, we do not care for the time being. If we know this, we can use it.
Next:
Exchanger: What about ten things?
A: data is exchanged between threads and used in concurrency. There is no confusion in the exchange process because of the large number of threads, and the interaction process is completed by the inspector if the message is sent and not received.
When will it be used?
A: Actually, it is rarely used, and there are few cases, but there are indeed such cases, Exchanger
Import Java. util. concurrent. exchanger; public class exchangertest {public static void main (string [] ARGs) {final exchanger <integer> exchanger = new exchanger <integer> (); For (INT I = 0; I <10; I ++) {final integer num = I; new thread () {public void run () {system. out. println ("I Am a thread: thread _" + this. getname () + "my data is:" + num); try {INTEGER exchangenum = exchanger. exchange (Num); thread. sleep (1, 1000); system. out. println ("I Am a thread: thread _" + this. getname () + "my original data is:" + num + ", and the exchanged data is:" + exchangenum);} catch (interruptedexception e) {e. printstacktrace ();}}}. start ();}}}
Here, you can see that if a thread and another thread transmit data, the data it receives must be transmitted to another thread, and the intermediate steps are controlled by exchanger, as a matter of fact, you can say that I randomly select the algorithm, but the algorithm logic in the middle is more complicated.
Next:
Cyclicbarrier, level mode, what is it about?
A: It is useful to go down when you need to get stuck in many links and require multiple threads to be reached at the same time.
Can you give an example?
A, trigger, and everyone starts like crazy.
The example below is also presented as a tour:
Import Java. util. concurrent. brokenbarrierexception; import Java. util. concurrent. extends icbarrier; public class barriertest {Private Static final int thread_count = 10; private final static extends icbarrier extends ic_barrier = new extends icbarrier (thread_count, new runnable () {public void run () {system. out. println ("======> I am a tour guide. This is the end of the call and I am going to take the next step! ") ;}}); Public static void main (string [] ARGs) throws interruptedexception, brokenbarrierexception {for (INT I = 0; I <10; I ++) {New thread (string. valueof (I) {public void run () {try {system. out. println ("I Am a thread:" + this. getname () + "let's get to the Travel location! "); Javasic_barrier.await (); system. Out. println (" I Am a thread: "+ this. getname () +" I started cycling! "); Cyclic_barrier.await (); system. Out. println (" I Am a thread: "+ this. getname () +" We started to climb the mountains! "); Cyclic_barrier.await (); system. Out. println (" I Am a thread: "+ this. getname () +" Let's go back to the hotel to rest! "); Cyclic_barrier.await (); system. Out. println (" I Am a thread: "+ this. getname () +" We started to ride home! "); Maid (); system. Out. println (" I Am a thread: "+ this. getname () +" we're home! ");} Catch (interruptedexception e) {e. printstacktrace ();} catch (brokenbarrierexception e) {e. printstacktrace () ;}}. Start ();}}}
In the test results, we can find that after going through a certain step, the tour guide said, "I am a tour guide. This time the name is over and you are going to take the next step !", Then we will proceed to the next step. OK, it's a bit interesting. In fact, horse racing is also the truth, but there is usually only one step for horse racing, so we have another way:
CountdownlatchCountdownlatch is used as a counter, so it cannot be reused. If you want to use it multiple times, you need to create a new one. In our code below, we use two sets of horse racing, each with five participants to perform a simple test:
Import Java. util. concurrent. countdownlatch; public class countdownlatchtest {private final static int group_size = 5; public static void main (string [] ARGs) {processonegroup ("group 1 "); processonegroup ("group 2");} Private Static void processonegroup (final string groupname) {final ready start_count_down = new counter (1); final ready end_count_down = new countdownlatch (group_size); System. Out. println ("====================================>\ N group: "+ groupname +" Start: "); For (INT I = 0; I <group_size; I ++) {New thread (string. valueof (I) {public void run () {system. out. println ("I Am a thread group: [" + groupname + "], Number:" + this. getname () + "thread, I'm ready! "); Try {start_count_down.await (); // wait for the start command to be issued: start_count_down.countdown ();} catch (interruptedexception e) {e. printstacktrace ();} system. out. println ("I Am a thread group: [" + groupname + "], Number:" + this. getname () + "thread, I have completed the execution! "); End_count_down.countdown ();}}. start () ;}try {thread. sleep (1000);} catch (interruptedexception e) {e. printstacktrace ();} system. out. println ("Everybody, come on! "); Start_count_down.countdown (); // start the race try {end_count_down.await (); // wait until multiple runners end one by one} catch (interruptedexception e) {e. printstacktrace ();} system. out. println ("group:" + groupname + "the competition is over! ");}}
A little interesting. If you use multiple threads, isn't it a little troublesome, but you can useThreadWhen the thread is joined, the current thread (generally the main thread) will wait until the corresponding thread executes the run method, to simulate it, we can also play with it:
Public class threadjointest {private final static int group_size = 5; public static void main (string [] ARGs) throws interruptedexception {thread [] threadgroup1 = new thread [5]; thread [] threadgroup2 = new thread [5]; for (INT I = 0; I <group_size; I ++) {final int num = I; threadgroup1 [I] = new thread () {public void run () {Int J = 0; while (J ++ <10) {system. out. println ("I Am a thread in group 1:" + num + "this is my number:" + J + "Run! ") ;}}; Threadgroup2 [I] = new thread () {public void run () {Int J = 0; while (J ++ <10) {system. out. println ("I Am a thread in group 2:" + num + "this is my number:" + J + "Run! ") ;}}; Threadgroup1 [I]. start () ;}for (INT I = 0; I <group_size; I ++) {threadgroup1 [I]. join ();} system. out. println ("-=> thread group 1 is running out. It's time to roll back! "); For (INT I = 0; I <group_size; I ++) {threadgroup2 [I]. start () ;}for (INT I = 0; I <group_size; I ++) {threadgroup2 [I]. join ();} system. out. println ("All finished! Haha, go home and have porridge! ");}}
Isn't the code complicated? Well, let's look at the above semaphores. If you don't need a tool, what will you do if you write it yourself? We simulate the CAS lock and use atomic to complete the work. Come and have fun:
Import Java. util. concurrent. atomic. atomicinteger; public class threadwaitpolicy {private final static int thread_count = 100; private final static int query_max_length = 2; private final static atomicinteger now_call_count = new atomicinteger (0 ); public static void main (string [] ARGs) throws interruptedexception {thread [] threads = new thread [thread_count]; for (INT I = 0; I <thread_count; I ++) {threa DS [I] = new thread (string. value of (I) {synchronized public void run () {int nowvalue = now_call_count.get (); While (true) {If (nowvalue <query_max_length & now_call_count.compareandset (nowvalue, nowvalue + 1) {break; // obtained} Try {This. wait (1000);} catch (interruptedexception e) {e. printstacktrace ();} nowvalue = now_call_count.get (); // obtain a data record for comparison} system. out. println (this. getname () + "====== I started the operation! "); Try {thread. sleep (1000);} catch (interruptedexception e) {e. printstacktrace ();} system. out. println (this. getname () + "===== the operation is complete! "); Now_call_count.getanddecrement (); this. running y () ;};}for (INT I = 0; I <thread_count; I ++) {threads [I]. start ();}}}
It is a bit interesting. In this way, most people will be dizzy with the while loop part, mainly to constantly judge and try. By default, wait () will be waiting for a long time, but we don't want him to wait for a long time. We will wait for 1 s and try again. In fact, we can change the example to a random time range for wait, which will make the simulation better; in addition, in the actual code, if the lock is obtained, the notify method should be placed in finally to ensure that he will certainly execute the notify method.
OK. This article is just for use. I hope to have a good time. We will gradually introduce its implementation mechanism and the easy-to-use mechanism in a write thread, but it is not frequently used.