Inter thread communication

wait/notify mechanism

principle

Only threads with the same lock can implement the wait/notify mechanism
The wait method is a method of the Object class. Its function is to make the thread currently executing the wait method wait, pause the execution at the code where the wait is located, and release the lock until it is notified or interrupted. Before you call wait, you must get the Object level lock of the Object, that is, you can only invoke the wait method in the synchronization method or the synchronous code block. The notification mechanism enables a thread to continue executing the code behind the wait. The selection of the thread is determined in the order of executing wait method, and the lock needs to be re obtained. If there is no lock when calling wait, an exception is thrown
The notify method should also be used in the synchronization method or synchronization code block. Before calling, the thread must obtain the lock. This method is used to notify other threads that may wait for the lock. If multiple threads wait, the thread in the wait state will be notified in the order of executing the wait method, and the thread will regain the lock. After the notify method is executed, the current thread will not release the lock immediately, and the thread in the wait state cannot obtain the object lock immediately. The current thread will not release the lock until the thread executing the notify method finishes executing, that is, after exiting the synchronized synchronization code block. When the wait thread that obtains the object finishes running, it will release the lock, If the notify statement is not used again at this time, other threads in the wait state will continue to be in the wait state because they are not notified
Summary: the wait method suspends the thread, and the notify method notifies the suspended thread to continue running

Basic use of wait / notify method

package P193;

import javafx.beans.binding.ObjectExpression;
import jdk.nashorn.internal.ir.CatchNode;

public class MyThread1 extends Thread {
    private Object lock;
    public MyThread1(Object object){
        super();
        this.lock=object;
    }

    @Override
    public void run() {
        super.run();
        try {
            synchronized (lock) {
                System.out.println("begin ,wait time=" + System.currentTimeMillis());
                lock.wait();
                System.out.println("end ,wait time=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

package P193;

import javafx.beans.binding.ObjectExpression;

public class MyThread2 extends Thread {
    private Object lock;
    public MyThread2(Object lock){
        this.lock=lock;
    }

    @Override
    public void run() {
        super.run();
        synchronized (lock){
            System.out.println("begin ,notify time="+System.currentTimeMillis());
            lock.notify();
            System.out.println("end ,notify time="+System.currentTimeMillis());
        }
    }
}

package P193;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        MyThread1 myThread1 = new MyThread1(lock);
        MyThread2 myThread2 = new MyThread2(lock);
        myThread1.start();
        Thread.sleep(3000);
        myThread2.start();
    }
}

Thread state switching

  • establish
    new Thread()
  • be ready
    The new thread enters the ready state after calling the start method. If the thread grabs CPU resources, the thread enters the running state
    The thread entering the ready state can be divided into the following four situations:
  1. The elapsed time after calling the sleep method exceeds the specified sleep time
  2. The thread got the monitor that was trying to synchronize
  3. A thread is waiting for a notification and another thread has sent a notification
  4. The resume method was called by a thread that is suspended
  • function
    Run run method
  • block
    There are five types of blocking:
  1. The thread calls the sleep method and voluntarily gives up the occupied processor resources
  2. The thread called the blocking I/O method, and the thread was blocked before the method returned
  3. Thread attempted to get a synchronization monitor, but the monitor is being held by another thread
  4. Thread waiting for a notify
  5. The program calls the suspend method, which is easy to cause deadlock. Try to avoid using it
  • Destroy
    After the run method runs, it enters the destruction phase, and the whole thread is executed

notify and notifyAll

Each time the notify method is called, only one thread is notified to wake up. The ring sequence is consistent with the sequence of executing the wait method; The notifyAll method will wake up other threads in reverse order of the wait method

wait(long)

The function of wait(long) enables you to wait for whether a thread wakes up the notify notification within a certain time. If it exceeds this time, the thread will wake up automatically. The lock will be held again on the premise that it can continue to run downward

package P213;

import com.sun.corba.se.impl.orbutil.CacheTable;
import com.sun.xml.internal.bind.v2.model.annotation.RuntimeAnnotationReader;

import javax.naming.event.ObjectChangeListener;
import java.util.PrimitiveIterator;

public class MyRunnable {
    static private Object lock=new Object();
    static private Runnable runnable=new Runnable() {
        @Override
        public void run() {
            try {
                synchronized (lock){
                    System.out.println("wait begin timer="+System.currentTimeMillis());
                    lock.wait(5000);
                    System.out.println("wait end timer="+System.currentTimeMillis());
                }
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    };

    public static void main(String[] args) {
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

Producer and consumer model

Single production and single consumption: operation values

package P225;

public class ValueObject {
    public static String value="";
}

package P225;

import com.sun.xml.internal.bind.v2.model.core.ElementPropertyInfo;
import sun.awt.SunHints;

public class P {
    private Object lock;
    public P(Object lock){
        this.lock=lock;
    }
    public void setValue(){
        try{
            synchronized (lock){
                if(!ValueObject.value.equals("")){
                    lock.wait();
                }
                String value=System.currentTimeMillis()+"_"+System.nanoTime();
                System.out.println("set The values are:"+value);
                ValueObject.value=value;
                lock.notify();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P225;

import sun.awt.SunHints;

public class C {
    private Object lock;
    public C(Object lock){
        this.lock=lock;
    }
    public void getValue(){
        try{
            synchronized (lock){
                if(ValueObject.value.equals("")){
                    lock.wait();
                }
                System.out.println("get The value of is:"+ValueObject.value);
                ValueObject.value="";
                lock.notify();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P225;

public class Pthread extends Thread {
    private P p;
    public Pthread(P p){
        this.p=p;
    }

    @Override
    public void run() {
        while(true){
            p.setValue();
        }
    }
}

package P225;

public class Cthread extends Thread {
    private C c;
    public Cthread(C c){
        this.c=c;
    }

    @Override
    public void run() {
        while(true){
            c.getValue();
        }
    }
}

package P225;

import javax.naming.event.ObjectChangeListener;

public class Run {
    public static void main(String[] args) {
        Object object=(Object) new String("");
        C c = new C(object);
        P p = new P(object);
        Pthread pthread = new Pthread(p);
        Cthread cthread = new Cthread(c);
        pthread.start();
        cthread.start();
    }
}

Multi production and multi consumption: operating value (fake death)

The phenomenon of "fake death" is that all threads enter the waiting state, and the whole project is in the stopped state and cannot continue to run. The reason is that the producer or consumer may wake up the same kind continuously. The solution is to replace notify with notifyAll

package P231;

public class ValueObject {
    public static String value="";
}

package P231;

public class P {
    private Object lock;
    public P(Object lock){
        this.lock=lock;
    }

    public void setValue(){
        try{
            synchronized (lock){
                while(!ValueObject.value.equals("")){
                    System.out.println("producer "+Thread.currentThread().getName()+" WAITING***");
                    lock.wait();
                }
                System.out.println("producer "+Thread.currentThread().getName()+" RUNNING-----");
                String value=System.currentTimeMillis()+"--"+System.nanoTime();
                ValueObject.value=value;
                lock.notify();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P231;

public class C {
    private Object lock;
    public C(Object lock){
        this.lock=lock;
    }
    public void getValue(){
        try{
            synchronized (lock){
                while(ValueObject.value.equals("")){
                    System.out.println("consumer  "+Thread.currentThread().getName()+"  WAITING***");
                    lock.wait();
                }
                System.out.println("consumer  "+Thread.currentThread().getName()+"  RUNNING");
                ValueObject.value="";
                lock.notify();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P231;

public class Pthread extends Thread {
    private P p;
    public Pthread(P p){
        this.p=p;
    }

    @Override
    public void run() {
        while(true){
            p.setValue();
        }
    }
}

package P231;

public class Cthread extends Thread {
    private C c;
    public Cthread(C c){
        this.c=c;
    }

    @Override
    public void run() {
        while(true){
            c.getValue();
        }
    }
}

package P231;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Object lock = (Object) new String("");
        P p = new P(lock);
        C c = new C(lock);
        Pthread[] pthreads=new Pthread[2];
        Cthread[] cthreads = new Cthread[2];

        for (int i = 0; i < 2; i++) {
            pthreads[i]=new Pthread(p);
            cthreads[i]=new Cthread(c);

            pthreads[i].setName("producer"+i);
            cthreads[i].setName("consumer"+i);

            pthreads[i].start();
            cthreads[i].start();
        }
    }
}

Single production and multi consumption: operation stack

The producer wants to put data into the List object, and uses multiple consumers to take data out of the List stack, assuming that the maximum capacity of the List is 1

package P233;

import jdk.nashorn.internal.runtime.linker.LinkerCallSite;

import java.beans.IntrospectionException;
import java.util.ArrayList;
import java.util.List;
import java.util.PrimitiveIterator;

public class MyStack {
    private List list=new ArrayList();

    public void push(){
        try {
            synchronized (this){
                if(list.size()==1){
                    this.wait();
                }
                list.add("anything="+ Math.random());
                this.notify();
                System.out.println("Push="+list.size());
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public void pop(){
        try{
            synchronized (this){
                if(list.size()==0){
                    this.wait();
                }
                String value=" "+list.get(0);
                list.remove(0);
                this.notify();
                System.out.println("Pop="+list.size());
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P233;

import P193.MyThread2;
import com.sun.javafx.scene.control.behavior.TwoLevelFocusPopupBehavior;

import java.util.List;

public class Pthread extends Thread {
    private MyStack mystack;
    public Pthread(MyStack myStack){
        this.mystack= myStack;
    }

    @Override
    public void run() {
        while (true){
            mystack.push();
        }
    }
}

package P233;

public class Cthread extends Thread {
    private MyStack myStack;
    public Cthread(MyStack myStack){
        this.myStack=myStack;
    }

    @Override
    public void run() {
        while (true){
            myStack.pop();
        }
    }
}

package P233;

import java.awt.*;
import java.util.ArrayList;

public class Run {
    public static void main(String[] args) {
        MyStack myStack=new MyStack();
        Pthread pthread = new Pthread(myStack);
        Cthread cthread = new Cthread(myStack);
        pthread.start();
        cthread.start();

    }
}

Multi production and one consumption: operation stack

package P233;

import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
import org.w3c.dom.ls.LSInput;

import java.beans.IntrospectionException;
import java.util.ArrayList;
import java.util.List;
import java.util.PrimitiveIterator;

public class MyStack {
    private List list=new ArrayList();

    public void push(){
        try {
            synchronized (this){
                while(list.size()==1){
                    this.wait();
                }
                list.add("anything="+ Math.random());
                this.notifyAll();
                System.out.println("Push="+list.size()+"  "+Thread.currentThread().getName()+"  "+ list.size());
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public void pop(){
        try{
            synchronized (this){
                while(list.size()==0){
                    this.wait();
                }
                String value=" "+list.get(0);
                list.remove(0);
                this.notifyAll();
                System.out.println("Pop="+list.size()+" "+Thread.currentThread().getName()+"  "+list.size());
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P233;

public class Cthread extends Thread {
    private MyStack myStack;
    public Cthread(MyStack myStack){
        this.myStack=myStack;
    }

    @Override
    public void run() {
        while (true){
            myStack.pop();
        }
    }
}

package P233;

import P193.MyThread2;
import com.sun.javafx.scene.control.behavior.TwoLevelFocusPopupBehavior;

import java.util.List;

public class Pthread extends Thread {
    private MyStack mystack;
    public Pthread(MyStack myStack){
        this.mystack= myStack;
    }

    @Override
    public void run() {
        while (true){
            mystack.push();
        }
    }
}

package P233;

import java.awt.*;
import java.util.ArrayList;

public class Run {
    public static void main(String[] args) {
        MyStack myStack=new MyStack();
        Pthread pthread1 = new Pthread(myStack);
        Pthread pthread2 = new Pthread(myStack);
        Pthread pthread3 = new Pthread(myStack);
        Pthread pthread4 = new Pthread(myStack);
        Cthread cthread = new Cthread(myStack);
        pthread1.start();
        pthread2.start();
        pthread3.start();
        pthread4.start();
        cthread.start();

    }
}

Continuous production and continuous consumption

package P243;

import P139.ThreadA;
import sun.text.normalizer.UBiDiProps;

import java.util.ArrayList;
import java.util.List;

public class Box {
    public List list=new ArrayList();
    synchronized public void add(){
            try{
                while(list.size()==15){
                    this.wait();
                }
                Thread.sleep(500);
                list.add("angthing");
                this.notifyAll();
                System.out.println("Thread:"+Thread.currentThread().getName()+"  "+"size="+list.size());
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
    }
    synchronized public void remove(){
            try{
                while(list.size()==0){
                    this.wait();
                }
                Thread.sleep(500);
                list.remove(0);
                this.notifyAll();
                System.out.println("Thread:"+Thread.currentThread().getName()+"  "+"size="+list.size());
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
    }
}

package P243;

public class Pthread extends Thread {
    private Box box;
    public Pthread(Box box){
        this.box=box;
    }

    @Override
    public void run() {
        while (true){
            box.add();
        }
    }
}

package P243;

import com.sun.org.apache.xpath.internal.WhitespaceStrippingElementMatcher;

public class Cthread extends Thread {
    private Box box;
    public Cthread(Box box){
        this.box=box;
    }

    @Override
    public void run() {
        while(true){
            box.remove();
            Thread.yield();
        }
    }
}

package P243;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Box box = new Box();
        Pthread pthread1 = new Pthread(box);
        pthread1.setName("Producer 1");
        Pthread pthread2 = new Pthread(box);
        pthread2.setName("Producer 2");
        Cthread cthread1 = new Cthread(box);
        cthread1.setName("Consumer 1");
        pthread1.start();
        pthread2.start();
        cthread1.start();
    }
}

Inter thread communication through pipeline

Java provides a variety of input and output streams to facilitate our operations on data. Among them, pipeline streams are used to directly transfer data between different threads. One thread sends data to the pipeline, the other thread reads data from the input pipeline, and realizes the communication between different threads through the pipeline

Byte stream

PipedInputStream and PipedOutputStream

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class Test {
        public static void main(String[] args) {
            PipedInputStream in = new PipedInputStream();
            PipedOutputStream out = new PipedOutputStream();
            try {
                in.connect(out);
                out.write("test".getBytes("utf8"));
                out.close();
                byte[] bytes = new byte[100];
                in.read(bytes);
                System.out.println(new String(bytes, "utf8"));
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
}
package P251;

import java.io.IOException;
import java.io.PipedOutputStream;

public class WriteData {
    public void writeMethod(PipedOutputStream out) {
        try {
            System.out.println("write:");
            for (int i = 0; i < 100; i++) {
                String outData = "" + (i + 1);
                try {
                    out.write(outData.getBytes("utf8"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package P251;

import java.io.IOException;
import java.io.PipedInputStream;

public class ReadData {
    public void readMethod(PipedInputStream in){
        try{
            System.out.println("read:");
            byte[] bytes = new byte[20];
            int k=in.read(bytes);
            while(k!=-1){
                String s = new String(bytes, 0, k);
                System.out.println(s);
                k=in.read(bytes);
            }
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


package P251;

import java.io.PipedOutputStream;

public class WriteThread extends Thread {
    private WriteData writeData;
    private PipedOutputStream pipedOutputStream;
    public WriteThread(WriteData writeData,PipedOutputStream pipedOutputStream){
        this.writeData=writeData;
        this.pipedOutputStream=pipedOutputStream;
    }

    @Override
    public void run() {
        writeData.writeMethod(pipedOutputStream);
    }
}

package P251;

import java.io.PipedInputStream;

public class ReadThread extends Thread {
    private ReadData readData;
    private PipedInputStream pipedInputStream;
    public ReadThread(ReadData readData,PipedInputStream pipedInputStream){
        this.readData=readData;
        this.pipedInputStream=pipedInputStream;
    }

    @Override
    public void run() {
        readData.readMethod(pipedInputStream);
    }
}

package P251;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class Run {
    public static void main(String[] args) throws InterruptedException, IOException {
        WriteData writeData = new WriteData();
        ReadData readData = new ReadData();
        PipedInputStream pipedInputStream = new PipedInputStream();
        PipedOutputStream pipedOutputStream = new PipedOutputStream();

        pipedInputStream.connect(pipedOutputStream);

        ReadThread readThread = new ReadThread(readData, pipedInputStream);
        WriteThread writeThread = new WriteThread(writeData, pipedOutputStream );

        readThread.start();
        Thread.sleep(2000);
        writeThread.start();
    }
}

Character stream

package P253;

import java.io.IOException;
import java.io.PipedWriter;

public class WriteData {
    public void writeMethod(PipedWriter out){
        System.out.println("write:");
        for(int i=0;i<100;i++){
            String data=""+(i+1);
            try {
                out.write(data);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package P253;

import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedReader;

public class ReadData {
    public void readMethod(PipedReader in){
        try{
            System.out.println("read:");
            char[] chars = new char[20];
            int k=in.read(chars);
            while(k!=-1){
                String s = new String(chars, 0, k);
                System.out.println(s);
                k=in.read(chars);
            }
        }
        catch (IOException e){
            e.printStackTrace();
        }

    }
}

package P253;

import com.sun.corba.se.impl.ior.WireObjectKeyTemplate;

import java.io.PipedWriter;

public class Wthread extends Thread {
    private WriteData writeData;
    private PipedWriter pipedWriter;
    public Wthread(WriteData writeData,PipedWriter pipedWriter){
        this.writeData= writeData;
        this.pipedWriter=pipedWriter;
    }

    @Override
    public void run() {
        writeData.writeMethod(pipedWriter);
    }
}

package P253;

import java.io.PipedReader;

public class Rthread extends Thread {
    private ReadData readData;
    private PipedReader pipedReader;
    public Rthread(ReadData readData,PipedReader pipedReader){
        this.readData=readData;
        this.pipedReader=pipedReader;
    }

    @Override
    public void run() {
        readData.readMethod(pipedReader);
    }
}

package P253;

import P233.Pthread;

import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;

public class Run {
    public static void main(String[] args) throws InterruptedException, IOException {
        WriteData writeData = new WriteData();
        ReadData readData = new ReadData();
        PipedWriter pipedWriter = new PipedWriter();
        PipedReader pipedReader = new PipedReader();

        pipedReader.connect(pipedWriter);

        Wthread wthread = new Wthread(writeData, pipedWriter);
        Rthread rthread = new Rthread(readData, pipedReader);

        rthread.start();
        Thread.sleep(2000);
        wthread.start();
    }
}

wait/notify to realize circular printing

Cycle print AB

package P257;

import sun.util.resources.cldr.de.CalendarData_de_AT;

import java.util.PrimitiveIterator;

public class Service {
    volatile private boolean printA=false;

    synchronized public void A(){
        try {
            while(printA==false){
                this.wait();
            }
            System.out.println("A"+'-'+Thread.currentThread().getName()+"  ");
            Thread.sleep(100);
            printA=false;
            this.notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized public void B(){
        try {
            while(printA==true){
                this.wait();
            }
            System.out.println("B"+"-"+Thread.currentThread().getName()+"  ");
            Thread.sleep(100);
            printA=true;
            this.notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P257;

public class Athread extends Thread {
    private Service service;
    public Athread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while(true){
            service.A();
        }
    }
}

package P257;

import javax.swing.event.TreeWillExpandListener;

public class Bthread extends Thread {
    private Service service;
    public Bthread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while (true){
            service.B();
        }
    }
}

package P257;

public class Run {
    public static void main(String[] args) {
        Service service = new Service();
        for (int i = 0; i < 2; i++) {
            Athread athread = new Athread(service);
            Bthread bthread = new Bthread(service);
            athread.start();
            bthread.start();
        }
    }
}

Cycle ABC

package PrintABC;

public class Service {
    volatile private boolean printA=true;
    volatile private boolean printB=false;
    volatile private boolean printC=false;

    synchronized public void printA(){
        try {
            while(printA==false){
                this.wait();
            }
            System.out.println("A");
            printA=false;
            printB=true;
            printC=false;
            Thread.sleep(100);
            notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized public void printB(){
        try {
            while(printB==false){
                this.wait();
            }
            System.out.println("B");
            printA=false;
            printB=false;
            printC=true;
            Thread.sleep(100);
            notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized public void printC(){
        try {
            while(printC==false){
                this.wait();
            }
            System.out.println("C");
            printA=true;
            printB=false;
            printC=false;
            Thread.sleep(100);
            notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

}

package PrintABC;

public class Athread extends Thread {
    private Service service;
    public Athread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while (true){
            service.printA();
        }
    }
}

package PrintABC;

import com.sun.xml.internal.ws.runtime.config.TubelineFeatureReader;

public class Bthread extends Thread {
    private Service service;
    public Bthread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while (true){
            service.printB();
        }
    }
}

package PrintABC;

import javafx.scene.control.cell.CheckBoxTreeCell;

public class Cthread extends Thread {
    private Service service;
    public Cthread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while (true){
            service.printC();
        }
    }
}

package PrintABC;

import P115.ThreadB;

import java.security.PublicKey;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();

        Athread athread = new Athread(service);
        Bthread bthread = new Bthread(service);
        Cthread cthread = new Cthread(service);
        athread.start();
        Thread.sleep(2000);
        bthread.start();
        Thread.sleep(2000);
        cthread.start();
    }
}

join method

The function of the join method is to enable the thread object to execute the tasks in the run method normally. Instead, the current thread is blocked indefinitely, and the code behind the current thread can be executed after the thread is destroyed. It has the effect of serial execution

join

package P264;

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            System.out.println("run begin Time="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("run end TImer="+System.currentTimeMillis());
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("main begin timer="+System.currentTimeMillis());
        myThread.join();
        System.out.println("main end timer="+System.currentTimeMillis());
    }
}

join(long)

package P264;

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            System.out.println("run begin Time="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("run end TImer="+System.currentTimeMillis());
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("main begin timer="+System.currentTimeMillis());
        myThread.join(2000);
        System.out.println("main end timer="+System.currentTimeMillis());
    }
}

The difference between join(long) and sleep(long)

The function of the join(long) method is implemented internally using the wait(long) method, so the join(long) method has the characteristics of releasing locks

sleep(long) release lock

package P265;

public class ThreadB extends Thread {
    @Override
    public void run() {
        try {
            System.out.println("b begin time="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("b end time="+System.currentTimeMillis());
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized  public void bService(){
        System.out.println("Print bService time="+System.currentTimeMillis());
    }
}


package P265;

public class ThreadA extends Thread {
    private ThreadB threadB;
    public ThreadA(ThreadB threadB){
        this.threadB=threadB;
    }

    @Override
    public void run() {
        try {
            synchronized (threadB){
                threadB.start();
                Thread.sleep(6000);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P265;

public class ThreadC extends Thread {
    private ThreadB threadB;
    public ThreadC(ThreadB threadB){
        this.threadB=threadB;
    }

    @Override
    public void run() {
        threadB.bService();
    }
}

package P265;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        ThreadB threadB = new ThreadB();
        ThreadA threadA = new ThreadA(threadB);
        threadA.start();
        Thread.sleep(1000);
        ThreadC threadC = new ThreadC(threadB);
        threadC.start();
    }
}

join(long) release lock

Modify the code of ThreadA, and the rest remain unchanged; Visible execution ThreadB The ThreadB lock is released after join() because the function of the join method is internally implemented using the wait method, so the join method releases the lock

package P265;

public class ThreadA extends Thread {
    private ThreadB threadB;
    public ThreadA(ThreadB threadB){
        this.threadB=threadB;
    }

    @Override
    public void run() {
        try {
            synchronized (threadB){
                threadB.start();
                threadB.join();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

Use of ThreadLocal class

The main function of class ThreadLocal is to put the data of the current Thread into the Map of the current Thread object, which is the instance variable of Thread class. Class ThreadLocal does not manage and store data. It is just a bridge between data and Map. It is used to put data into Map. The key in the Map stores the ThreadLocal object, and the value is the stored value. The Map value in each Thread is only visible to the current Thread.

Isolation of thread variables

package P279;

public class Tools {
    public static ThreadLocal t1=new ThreadLocal();
}

package P279;

public class MyThreadA extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                Tools.t1.set("A"+(i+1));
                System.out.println("A get "+Tools.t1.get());
                int sleepValue=(int)(Math.random()*1000);
                Thread.sleep(sleepValue);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P279;

public class MyThreadB extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                Tools.t1.set("B"+(i+1));
                System.out.println("   B get "+ Tools.t1.get());
                int i1 = (int) (Math.random() * 1000);
                Thread.sleep(i1);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P279;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyThreadA myThreadA = new MyThreadA();
        MyThreadB myThreadB = new MyThreadB();
        myThreadA.start();
        myThreadB.start();
        for (int i = 0; i < 10; i++) {
            Tools.t1.set("main  "+(i+1));
            System.out.println("      main get "+ Tools.t1.get());
            int sleepValue=(int)(Math.random()*1000);
            Thread.sleep(sleepValue);
        }
    }
}

get method

When calling the get method of ThreadLocal class for the first time, the return value is null. You can change the default initial value of get by inheriting ThreadLocal class and overriding the initialValue method inside. This method also has isolation

Use of class InheritableThreadLocal

ThreadLocal class cannot implement child thread value inheritance

package P287;

public class Tools {
    public static ThreadLocal t1=new ThreadLocal();
}

package P287;

public class ThreadA extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println("stay ThreaadA Value in thread:"+ Tools.t1.get());
                Thread.sleep(100);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P287;

public class Test {
    public static void main(String[] args) {
        try {
            for (int i = 0; i < 10; i++) {
                if(Tools.t1.get()==null){
                    Tools.t1.set("When this value main Thread put");
                }
                System.out.println("      stay main Value in thread="+ Tools.t1.get());
                Thread.sleep(100);
            }
            Thread.sleep(5000);
            ThreadA threadA = new ThreadA();
            threadA.start();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

InheritableThreadLocal reflects the inheritance of child thread values

Change ThreadLocal to inheritableThreadLocal class. The value obtained by the child thread ThreadA thread is inherited from the parent thread main

Keywords: Java Back-end Multithreading

Added by AffApprentice on Mon, 03 Jan 2022 18:58:12 +0200