Q Why learn multithreaded communication?
A Each thread has its own private thread thread within the thread, threads do not interfere with each other. To make the best use of server resources, we often need multiple threads to collaborate.
Business target, A, B two threads output in turn
package co.dianjiu.thread;
public class MyThreadNoLock {
static class MyThreadA implements Runnable{
@Override
public void run(a) {
for (int i = 0; i < 50; i++) {
System.out.println("MyThreadA===>"+ i); }}}static class MyThreadB implements Runnable{
@Override
public void run(a) {
for (int i = 0; i < 50; i++) {
System.out.println("MyThreadB===>"+ i); }}}public static void main(String[] args) {
new Thread(new MyThreadA()).start();
new Thread(newMyThreadB()).start(); }}Copy the code
The execution result
The execution sequence of thread A and thread B cannot be controlled
.
MyThreadB===>48
MyThreadA===>41
MyThreadB===>49
MyThreadA===>42
MyThreadA===>43
MyThreadA===>44
MyThreadA===>45
MyThreadA===>46
MyThreadA===>47
MyThreadA===>48
MyThreadA===>49
1. Use locks for thread communication
Depending on the thread and lock relationship, only one thread holds the lock at a time.
package co.dianjiu.thread;
public class MyThreadNoLock {
private static Object lock = new Object();
static class MyThreadA implements Runnable{
@Override
public void run(a) {
// Object lock to synchronize code blocks
synchronized (lock){
for (int i = 0; i < 50; i++) {
System.out.println("MyThreadA===>"+ i); }}}}static class MyThreadB implements Runnable{
@Override
public void run(a) {
// Object lock to synchronize code blocks
synchronized (lock){
for (int i = 0; i < 50; i++) {
System.out.println("MyThreadB===>"+ i); }}}}public static void main(String[] args) {
new Thread(new MyThreadA()).start();
new Thread(newMyThreadB()).start(); }}Copy the code
The execution result
You can control A to execute first, then B to execute, and get A little bit closer to the target
.
MyThreadA===>47
MyThreadA===>48
MyThreadA===>49
MyThreadB===>0
MyThreadB===>1
MyThreadB===>2
MyThreadB===>3.
Use wait notifications for communication
The basis of waiting notification mechanism is that two threads use the same object lock. After printing their own output, A and B wake up the other waiting thread, and then enter the waiting state and release the lock at the same time.
package co.dianjiu.thread;
public class MyThreadNoLock {
private static Object lock = new Object();
static class MyThreadA implements Runnable{
@Override
public void run(a) {
synchronized (lock){
for (int i = 0; i < 50; i++) {
try {
System.out.println("MyThreadA===>" + i);
lock.notify();
lock.wait();
} catch(InterruptedException e) { e.printStackTrace(); } } lock.notify(); }}}static class MyThreadB implements Runnable{
@Override
public void run(a) {
synchronized (lock){
for (int i = 0; i < 50; i++) {
try {
System.out.println("MyThreadB===>" + i);
lock.notify();
lock.wait();
} catch(InterruptedException e) { e.printStackTrace(); } } lock.notify(); }}}public static void main(String[] args) {
new Thread(new MyThreadA()).start();
new Thread(newMyThreadB()).start(); }}Copy the code
The execution result
At this point we have achieved our business goals.
.
MyThreadA===>45
MyThreadB===>45
MyThreadA===>46
MyThreadB===>46
MyThreadA===>47
MyThreadB===>47
MyThreadA===>48
MyThreadB===>48
MyThreadA===>49
MyThreadB===>49
Use semaphore for communication
The JDK provides a Semaphore class with “Semaphore” functionality, our own implementation of Semaphore communication based on the volatile keyword.
package co.dianjiu.thread;
public class MyThreadVolatile {
private static volatile int signal = 0;
static class MyThreadVolatileA implements Runnable {
@Override
public void run(a) {
while (signal < 50) {
if(signal % 2= =1) {
System.out.println("MyThreadA===>" + signal);
synchronized (this) {
signal=signal+1;
}
}
}
}
}
static class MyThreadVolatileB implements Runnable {
@Override
public void run(a) {
while (signal < 50) {
if(signal % 2= =0) {
System.out.println("MyThreadB===>" + signal);
synchronized (this) {
signal++;
}
}
}
}
}
public static void main(String[] args) {
new Thread(new MyThreadVolatileA()).start();
new Thread(newMyThreadVolatileB()).start(); }}Copy the code
The execution result
We can customize simple semaphore to achieve odd – and even – numbered thread printing.
.
MyThreadA===>43
MyThreadB===>44
MyThreadA===>45
MyThreadB===>46
MyThreadA===>47
MyThreadB===>48
MyThreadA===>49
MyThreadB===>50
4. Use pipe flow for communication
A pipeline stream is typically used for multithreaded IO stream operations.
Character streams PipedWriter, PipedReader
Byte stream PipedOutputStream, PipedInputStream
package co.dianjiu.thread;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
public class MyThreadPipe {
static class MyReaderThread implements Runnable{
private PipedReader reader;
public MyReaderThread(PipedReader reader) {
this.reader = reader;
}
@Override
public void run(a) {
System.out.println("MyReaderThread");
int receive = 0;
try {
while((receive = reader.read()) ! = -1) {
System.out.print((char)receive); }}catch(IOException e) { e.printStackTrace(); }}}static class MyWriterThread implements Runnable {
private PipedWriter writer;
public MyWriterThread(PipedWriter writer) {
this.writer = writer;
}
@Override
public void run(a) {
System.out.println("MyWriterThread");
int receive = 0;
try {
writer.write("https://dianjiu.co");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
writer.close();
} catch(IOException e) { e.printStackTrace(); }}}}public static void main(String[] args) throws IOException, InterruptedException {
PipedReader reader = new PipedReader();
PipedWriter writer = new PipedWriter();
// Create a link
writer.connect(reader);
new Thread(new MyReaderThread(reader)).start();
new Thread(newMyWriterThread(writer)).start(); }}Copy the code
The execution result
MyReaderThread MyWriterThread dianjiu.co
5. In-depth understanding of Join method
The source of the join() method
public final void join(a) throws InterruptedException {
// Wait for 0 ms and enter the wait state forever
join(0);
}
Copy the code
Join (long) method source
Parameter 1 is the number of milliseconds to wait
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
// The number of milliseconds is a value greater than 0
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
The number of milliseconds to wait is 0
if (millis == 0) {
// use a this.wait call loop conditional on this.isAlive; When the thread terminates, the this.notifyAll method is called.
while (isAlive()) {
//join() finally calls wait(0)
wait(0); }}else {
// use the this.wait call loop conditional on this.isAlive; When the thread terminates, the this.notifyAll method is called.
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break; } wait(delay); now = System.currentTimeMillis() - base; }}}Copy the code
Join (long, int) method source
Parameter 1 Wait time in milliseconds
Parameter 2 Wait time nanoseconds
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
// The number of milliseconds is a value greater than 0
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
// The number of nanoseconds ranges from 0 to 999999
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
// If the number of nanoseconds is less than 500000 and the number of milliseconds is 0, the wait time is 1 millisecond
// If the number of nanoseconds is greater than or equal to 500000 and the number of milliseconds is 0, the wait time is 1 millisecond
// If the number of nanoseconds is greater than or equal to 500000 and the number of milliseconds is not 0, the wait time is milliseconds +1
if (nanos >= 500000|| (nanos ! =0 && millis == 0)) {
millis++;
}
Join (); join(); join();
join(millis);
}
Copy the code
Let’s review how it’s used
package co.dianjiu.thread;public class MyThreadJoin extends Thread{ @Override public void run(a){ try { System.out.println("Sleep for a second."); Thread.sleep(1000); System.out.println("The child thread sleeps for a second."); } catch(InterruptedException e) { e.printStackTrace(); }}public static void main(String[] args) throws InterruptedException { MyThreadJoin a = new MyThreadJoin(); a.setName("a"); a.start(); System.out.println(a.getName() + "= = = >" + a.getState()); System.out.println(Thread.currentThread().getName() + "= = = >" + Thread.currentThread().getState()); System.out.println("Main thread, no join method completes first."); }}
Copy the code
A ===>RUNNABLE main===>RUNNABLE main thread. If no join method is executed, the child thread will finish sleeping for a second first
After adding the join method
package co.dianjiu.thread;public class MyThreadJoin extends Thread{ @Override public void run(a){ try { System.out.println("Sleep for a second."); Thread.sleep(1000); System.out.println("The child thread sleeps for a second."); } catch(InterruptedException e) { e.printStackTrace(); }}public static void main(String[] args) throws InterruptedException { MyThreadJoin a = new MyThreadJoin(); a.setName("a"); a.start(); a.join(); System.out.println(a.getName() + "= = = >" + a.getState()); System.out.println(Thread.currentThread().getName() + "= = = >" + Thread.currentThread().getState()); System.out.println("The main thread, with the join method, will wait for the subthread to finish executing before the main thread executes."); }}
Copy the code
The child thread TERMINATED main===>RUNNABLE sleeps one second. The primary thread TERMINATED main===>RUNNABLE sleeps one second. The primary thread TERMINATED main===>RUNNABLE sleeps one second
To summarize the function of join() method, calling the join method of Thread will make the current Thread enter the wait state and wait for the completion of join Thread before executing the current Thread.
6. In-depth understanding of Sleep methods
Sleep (long) method source
Parameter 1 millisecond
Public static native void sleep(long millis) throws InterruptedException;
Copy the code
Sleep (long, int) method source
Parameter 1 millisecond
Parameter 2 nanoseconds
public static void sleep(long millis, int nanos) throws InterruptedException { If (millis < 0) {throw new IllegalArgumentException("timeout value is negative"); } / / the number of nanoseconds value range of 0-999999 the if (nanos < 0 | | nanos > 999999) {throw new IllegalArgumentException (" nanosecond timeout value out of range"); } // If the number of nanoseconds is less than 500000 and the number of milliseconds is 0 then the sleep time is 1ms // If the number of nanoseconds is greater than or equal to 500000 and the number of milliseconds is 0 then the sleep time is 1ms // If the number of nanoseconds is greater than or equal to 500000, then the sleep time is 1ms. And milliseconds to 0 is not sleep time of milliseconds + 1 if (nanos > = 500000 | | (nanos! = 0 && millis == 0)) { millis++; Sleep (0) sleep(millis); }
Copy the code
Qsleep, JOIN, yield, wait? (Ali interview question)
Asleep(long) and Yield () are static methods of Thread. They do not release the lock, but release the CPU. The sleep method blocks, and yield returns to the ready state. Wait (), notify(), and notifyAll() are all java.lang.object methods that release the lock and CPU resources. After wait, the thread waits to wake up again (notify randomly, notifyAll wakes up). Automatic wake up at the end of a thread) is put into the lock pool to compete for the synchronization lock; Join () calls wait(), which also releases the lock but does not release the CPU. The current running thread calls another thread’s JOIN method, and the current thread enters the wait pool and waits for the other join thread to complete.
7. Understanding the ThreadLocal class
ThreadLocal is a thread-local variable or thread-local store. Strictly speaking, the ThreadLocal class does not communicate between multiple threads, but rather allows each thread to have its own “independent” variables that do not affect each other.
Eight, InheritableThreadLocal class
[InheritableThreadLocal] The InheritableThreadLocal class is a little different from the ThreadLocal class. It is not only the current thread that can access the replica value, but also its child threads.