In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article introduces the relevant knowledge of "how to realize the communication function between threads in Java". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Catalogue
Preface
1. How do I get two threads to execute in turn?
two。 How do I make two threads intersect in an orderly manner?
3. Thread D executes after the synchronous execution of A, B, and C is completed.
4. The three athletes are ready to run at the same time.
5. The child thread returns the result to the main thread
Preface
Although usually each child thread only needs to complete its own task, sometimes we want multiple threads to work together to complete a task, which involves inter-thread communication.
The methods and classes involved in this article on inter-thread communication include: thread.join (), object.wait (), object.notify (), CountdownLatch, CyclicBarrier, FutureTask, Callable.
Next, we will use several examples to show how to implement inter-thread communication in Java:
How do you get two threads to execute in turn, that is, one thread waits for the other thread to finish execution before executing?
How do I get two threads to intersect in an orderly manner?
There are four threads: a, B, C, D, how to implement D after the synchronous execution of A, B, C is completed?
The three athletes prepare separately, and then start running at the same time when everyone is ready.
After the child thread finishes the task, the result is returned to the main thread.
1. How do I get two threads to execute in turn?
Suppose there are two threads, An and B, both of which can print numbers sequentially, with the following code:
Public class Test01 {public static void main (String [] args) throws InterruptedException {demo1 ();} public static void demo1 () {Thread a = new Thread (()-> {printNumber ("A");}); Thread b = new Thread (()-> {printNumber ("B");}); a.start (); b.start () } public static void printNumber (String threadName) {int I = 0; while (iTunes +)
< 3) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadName + " print: " + i); } }} 得到的结果如下: A print: 1 B print: 1 B print: 2 A print: 2 A print: 3 B print: 3 可以看到 A 和 B 同时打印数字,如果我们希望 B 在 A 执行完成之后开始执行,那么可以使用 thread.join() 方法实现,代码如下: public static void demo2() { Thread a = new Thread(() ->{printNumber ("A");}); Thread b = new Thread (()-> {System.out.println ("B waits for An execution"); try {a.join ();} catch (InterruptedException e) {e.printStackTrace ();} printNumber ("B");}); a.start (); b.start ();}
The results are as follows:
B waits for A to execute
A print: 1
A print: 2
A print: 3
B print: 1
B print: 2
B print: 3
We can see that the a.join () method makes B wait for A to finish printing.
The purpose of the thread.join () method is to block the current thread and wait for the thread calling the join () method to finish executing before executing the following code.
To see the source code of the join () method, join (0) is called internally, as follows:
Public final void join () throws InterruptedException {join (0);}
Check the source code of join (0) as follows:
< 0) { throw new IllegalArgumentException("timeout value is negative"); } // 调用 join(0) 执行下面的代码 if (millis == 0) { // 这里使用 while 循环的目的是为了避免虚假唤醒 // 如果当前线程存活则调用 wait(0), 0 表示永久等待,直到调用 notifyAll() 或者 notify() 方法 // 当线程结束的时候会调用 notifyAll() 方法 while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay { synchronized (lock) { System.out.println("A 1"); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("A 2"); System.out.println("A 3"); } }); Thread B = new Thread(() ->{synchronized (lock) {System.out.println ("B1"); System.out.println ("B2"); System.out.println ("B3"); lock.notify ();}}); A.start (); B.start ();}
The results are as follows:
A 1
B 1
B 2
B 3
A 2
A 3
The execution process of the above code is as follows:
First, let's create an object lock shared by An and B: lock = new Object ()
When A gets the lock, print 1 first, then call the lock.wait () method to enter the waiting state, and then hand over control of the lock.
B will not be executed until A calls the lock.wait () method to release control and B acquires the lock
After B gets the lock, print 1pm 2pm 3, and then call the lock.notify () method to wake up the waiting A
A wakes up and continues to print the remaining 2BI 3.
To make it easier to understand, I added the above code to the log, as follows:
Public static void demo3 () {Object lock = new Object (); Thread A = new Thread (()-> {System.out.println ("INFO:A waiting to acquire lock"); synchronized (lock) {System.out.println ("INFO:An acquires lock"); System.out.println ("A1") Try {System.out.println ("INFO:An enters the waiting state, relinquishes control of the lock"); lock.wait ();} catch (InterruptedException e) {e.printStackTrace ();} System.out.println ("INFO:A wakes up by B to continue execution") System.out.println ("A 2"); System.out.println ("A 3");}}); Thread B = new Thread (()-> {System.out.println ("INFO:B waiting to acquire lock"); synchronized (lock) {System.out.println ("INFO:B acquires lock") System.out.println ("B 1"); System.out.println ("B 2"); System.out.println ("B 3"); System.out.println ("INFO:B execution ends, call notify method to wake up A"); lock.notify ();}}); A.start (); B.start ();}
The results are as follows:
INFO:A waits to acquire the lock
INFO:An acquires the lock
A 1
INFO:An enters waiting state and relinquishes control of the lock
INFO:B waits to acquire the lock
INFO:B acquires the lock
B 1
B 2
B 3
When the execution of INFO:B ends, call the notify method to wake up A
INFO:An is awakened by B to continue execution.
A 2
A 3
3. Thread D executes after the synchronous execution of A, B, and C is completed.
The method described earlier in thread.join () allows one thread to continue execution after waiting for another thread to finish running. But if we add A, B, and C to the D thread in turn, we will have A, B, and C execute in turn, and we want them to run synchronously.
The goal we want to achieve is that the three threads A, B, C can start running at the same time, and inform Dscape D that they will not start running after they have finished running independently, until A, B, and C are all finished. So we use CountdownLatch to implement this type of communication. Its basic usage is:
Create a counter and set an initial value, CountdownLatch countDownLatch = new CountDownLatch (3)
Call countDownLatch.await () to enter the waiting state until the count value becomes 0
Call countDownLatch.countDown () on another thread, which subtracts the count by one
When the value of the counter changes to 0, the method in the countDownLatch.await () wait thread continues to execute the following code.
The implementation code is as follows:
Public static void runDAfterABC () {int count = 3; CountDownLatch countDownLatch = new CountDownLatch (count); new Thread (()-> {System.out.println ("INFO: d waits for ABC to finish running"); try {countDownLatch.await (); System.out.println ("INFO: ABC finishes running, D starts running"); System.out.println ("D is working") } catch (InterruptedException e) {e.printStackTrace ();}}). Start (); for (char threadName = 'Agar; threadName {System.out.println (name + "is working"); try {Thread.sleep (100);} catch (InterruptedException e) {e.printStackTrace () } System.out.println (name + "finished"); countDownLatch.countDown ();}. Start ();}}
The results are as follows:
INFO: d waits for A B C to finish running
An is working
B is working
C is working
C finished
B finished
A finished
INFO: A B C runs complete, D starts running
D is working
In fact, CountDownLatch itself is a countdown counter, we set the initial count value to 3. When D is running, first call the countDownLatch.await () method to check whether the value of the counter is 0, and keep waiting if it is not 0. After A, B, and C have finished running, use the countDownLatch.countDown () method to subtract the reciprocal counter by 1. The counter is reduced to 0, and the await () method is told to end the wait, and D starts to continue.
Therefore, CountDownLatch is suitable for situations where a thread needs to wait for multiple threads.
4. The three athletes are ready to run at the same time.
This time, the three threads A, B, and C all need to be prepared separately, and when the three threads are ready, they will start to run at the same time. How should we do this?
CountDownLatch can be used to count, but when the count is completed, only one await () method of one thread will get a response, so multiple threads cannot be triggered at the same time. To achieve the effect of threads waiting for each other, we can use this CyclicBarrier, which is basically used as follows:
First create a public object, CyclicBarrier, and set the number of threads waiting at the same time, CyclicBarrier cyclicBarrier = new CyclicBarrier (3)
These threads start to prepare at the same time, and when they are ready, they need to wait for others to be ready, so call the cyclicBarrier.await () method to wait for others.
When the specified threads that need to wait at the same time call the cyclicBarrier.await () method, it means that the threads are ready, and the threads will start to continue to execute at the same time.
Imagine that there are three runners who need to start running at the same time, so they need to wait for everyone else to be ready. The implementation code is as follows:
Public static void runABCWhenAllReady () {int count = 3; CyclicBarrier cyclicBarrier = new CyclicBarrier (count); Random random = new Random (); for (char threadName = 'Agar; threadName {int prepareTime = random.nextInt (10000); System.out.println (name + "preparation time:" + prepareTime); try {Thread.sleep (prepareTime)) } catch (InterruptedException e) {e.printStackTrace ();} System.out.println (name + "ready, waiting for someone else"); try {cyclicBarrier.await ();} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace () } System.out.println (name + "start running");}) .start ();}}
The results are as follows:
A preparation time: 1085
B preparation time: 7729
C preparation time: 8444
A ready, waiting for the others
B ready, waiting for the others
C is ready, waiting for the others
C started running.
A start running
B start running
The function of CyclicBarrier is to wait for multiple threads to execute simultaneously.
5. The child thread returns the result to the main thread
In actual development, we often need to create subthreads to do some time-consuming tasks, and then pass the execution results back to the main thread. So how do you implement it in Java?
Generally, when creating a thread, we pass the Runnable object to Thread execution. The source code of Runable is as follows:
@ FunctionalInterfacepublic interface Runnable {public abstract void run ();}
You can see that Runable is a functional interface, and the run method in this interface does not return a value, so if you want to return results, you can use another similar interface, Callable.
Functional interface: an interface with only one method
The source code of API Callable is as follows:
@ FunctionalInterfacepublic interface Callable {/ * * Computes a result, or throws an exception if unable to do so. * * @ return computed result * @ throws Exception if unable to compute a result * / V call () throws Exception;}
As you can see, the biggest difference between Callable is that it returns generics.
So the next question is, how do you pass back the results of the child threads? Java has a class, FutureTask, which works with Callable, but note that the method that get uses to get the results blocks the main thread. FutureTask is essentially a Runnable, so it can be passed directly to Thread.
For example, we want the child thread to calculate the sum of 1 to 100 and return the result to the main thread. The code is as follows:
Public static void getResultInWorker () {Callable callable = ()-> {System.out.println ("subtask starts"); Thread.sleep (1000); int result = 0; for (int I = 0; I)
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.