Multi-threaded study notes (two) multi-threaded thread communication

introduction

For a person, he will experience different states such as birth, old age, sickness, and death in his life. As the so-called water is impermanent, soldiers are impermanent. On the other hand, threads will also have different states after they are started. The states experienced by threads are relatively fixed. There are six states. From creation to death, a thread may experience the middle four states, or it may die from day to day. The life cycle diagram of a thread is shown below.
Insert picture description here

Thread and state

The following is the thread of six states in a computer, such as when a thread is loaded in the computer, there is usually six states: new, terminated, timed waiting, running, blocked, wait, the relationship between these six states are as follows:
Insert picture description here
Thread The creation and demise and the running status of the will not be repeated.

timed waiting

The timed waiting state is a timed waiting state. When we call Thread.sleep(xxx), we can enter the timed waiting state. For example, Thread.sleep(20) means that the thread enters the sleep waiting state of 20ms. After 20ms is over, the thread will automatically Wake up and compete for the lock object (that is, compete for cpu resource ownership). If the contention fails, it will enter the blocking state and wait for the next round of contention.
A specific example of how to enter timedwaiting is shown below.

public class SleepTest {
    public static int j=200;
    public static Object lock=new Object();;
    public static void main(String[] args) throws InterruptedException {
        //Object lock = new Object();
        new Thread(){
            @Override
            public void run() {
                super.setName("赵丽颖");
                synchronized (lock){
                    for (int i = 0; i < 50; i++) {
                        j--;
                        System.out.println("这是第:"+i+"--个"+Thread.currentThread().getName()+"线程"+":"+j);
                    }
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    for (int i = 0; i < 50; i++) {
                        j++;
                        System.out.println("这是第:"+i+"--个"+Thread.currentThread().getName()+"线程"+":"+j);
                    }
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"地里热巴").start();
        Thread.sleep(100);
        System.out.println("----------"+Thread.currentThread().getName()+":----------");
    }
}

The running results are as follows: The
Insert picture description here
above example uses the "implementation" Runnable interface and inherits the Thread class to implement multi-threaded programs, and uses synchronous code blocks as the synchronization technology, which simply solves the thread safety problem.

waiting

The infinite waiting state is waiting. The waiting state is not an operation of one thread. It reflects the communication between multiple threads. It can be understood as a cooperative relationship between multiple threads. Multiple threads will fight for locks and mutually interact. There is a collaborative relationship between. When multiple threads cooperate, such as A and B threads, if the A thread calls the wait() method in the Runnable state, then the A thread enters
the Waiting (infinite waiting) state and loses the synchronization lock. If at this time the B thread acquires the synchronization lock and calls the notify() method in the running state, then the A thread that is waiting indefinitely will be awakened. Attention is to wake up. If the lock object is acquired, the A thread will enter the Runnable (runnable) state after waking up; if the lock object is not acquired, it will enter the Blocked (lock blocked state).

blocked

For blocked, the losers of multiple threads competing for lock objects will enter a blocked state and wait for a new round of opportunities to grab CPU resources.

Intercommunication between threads

For mutual communication between threads, this problem is rather broad, multi-threaded communication between general, can be divided into shared memory mechanism and message communication mechanism , the following first introduced multi-threaded shared memory of the communication mechanism (for example with java).

Memory sharing mechanism

Memory sharing, as the name implies, is that two threads share a certain memory area, and the content of the shared memory area is used to achieve the purpose of thread communication. Shared memory is more common in this way, we often set a shared variable. Then multiple threads operate the same shared variable. So as to achieve the purpose of thread communication.
Insert picture description here
Common in memory sharing mechanism has polling mode and synchronous mode .

Polling mode

First, let’s discuss the polling mode of the first memory sharing communication mechanism. The polling mode is relatively simple. If there are two threads A and B, our requirement is to trigger the flag bit after program A is executed. If the flag bit matches The condition allows thread B to execute, which requires thread B to continuously poll whether the indicated bit meets the condition. If it meets the condition, it will start executing the program of thread B, otherwise it will not execute. This simply realizes the signal transmission between threads. Given the case of the little monkey, suppose that thread A makes flag become true every time it counts 5 times, thread B continuously polls the flag bit, and triggers the program in thread B when the conditions are met.
Defined logo class:

package com.itheima.demo01.polling;
public class MyFlag {
    private boolean flag ;
    public MyFlag(boolean flag) {
        this.flag = flag;
    }
    public MyFlag() {
    }
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

Thread A implements the runnable interface, and obviously implements the run method in the interface.

public class MyThreadA implements Runnable{
    private volatile MyFlag flag = new MyFlag();
    public MyThreadA(MyFlag flag) {
        this.flag = flag;
    }
    public MyFlag getFlag() {
        return flag;
    }
    public void setFlag(MyFlag flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        System.out.println("-----------"+Thread.currentThread().getName()+"正在执行------------------");
        while (true){
            if(!flag.isFlag()){
                for (int i = 1; i < 20; i++) {

                    System.out.println("----------------"+i+"-----------------");
                    if(i%5==0){
                        flag.setFlag(true);
                        System.out.println(flag.isFlag());
                    }else {
                        flag.setFlag(false);
                        System.out.println(flag.isFlag());
                    }
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
//        flag.setFlag(true);
//        System.out.println("-----------"+Thread.currentThread().getName()+"要退出了------------------");
    }
}

Thread B class inherits the Thread class and overrides the run method in the parent class.

public class MyThreadB extends Thread {
    private volatile MyFlag flag;
    public MyFlag getFlag() {
        return flag;
    }
    public void setFlag(MyFlag flag) {
        this.flag = flag;
    }

    public MyThreadB(MyFlag flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        super.setName("MyThreadB");
        while (true){
            if(flag.isFlag()){
                System.out.println("-----------"+Thread.currentThread().getName()+"将要开始了-------------------");
                try {
                    throw  new InterruptedException("线程B需要执行了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    System.out.println("-----------"+Thread.currentThread().getName()+"将要结束了-------------------");
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Finally, the test class is given

public class DemoTestPolling {
    public static void main(String[] args) {
        MyFlag flag = new MyFlag(false);
        new Thread(new MyThreadA(flag),"MyThreadA").start();
        new MyThreadB(flag).start();
    }
}

It should be noted here that the flag defined by MyFlag must be modified with the volatile keyword . This is very critical, otherwise the desired effect will not be achieved. The reason is that the Java memory model stipulates that all variables exist in main memory. Among them, each thread has its own working memory. All operations of threads on variables must be performed in the working memory, and cannot be directly operated on the main memory. And each thread cannot access the working memory of other threads. When the value of the variable is written back to the main memory from the working memory of the thread, but if thread A does not update the main memory in time, then thread B will have a dirty read phenomenon, so in order to ensure the atomicity of memory operations, the volatile keyword must be used Modification to ensure data synchronization between thread memory and main memory.
In the end, the results of Xiaoyuan's operation are as follows:
Insert picture description here
Insert picture description here

Synchronization mechanism

The synchronization mechanism is also a kind of memory sharing, and has been widely used to solve thread safety issues. The synchronization mechanism includes synchronization code blocks, synchronization methods and lock mechanisms. First of all, Xiao Yuan will introduce the usage of synchronized code blocks.

Synchronization code block

Go directly to the case and
define the ticket-buying thread class

public class RunnableImpl implements Runnable{
    //定义一个多个线程共享的票源
    private  int ticket = 1000;
    //创建一个锁对象
    Object obj = new Object();
    //设置线程任务:卖票
    @Override
    public void run() {
        //使用死循环,让卖票操作重复执行
        while(true){
           //同步代码块
            synchronized (obj){
                //先判断票是否存在
                if(ticket>0){
                    //提高安全问题出现的概率,让程序睡眠
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //票存在,卖票 ticket--
                    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                    ticket--;
                }
            }
        }
    }
}

Test class

public class Demo01Ticket {
    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        RunnableImpl runnable = new RunnableImpl();
        Thread thread1 = new Thread(runnable,"窗口一");
        Thread thread2 = new Thread(runnable,"窗口二");
        Thread thread3 = new Thread(runnable,"窗口三");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

Test results In the
Insert picture description hereInsert picture description here
above case, the lock of the synchronization code block uses the thread-defined obj class and solves the thread security problem caused by multiple threads accessing the ticket.

Synchronization method

The case is still buying tickets in different windows. This time the synchronization method is used to solve the thread safety problem. The
defined thread class

public class RunnableImpl implements Runnable{
    //定义一个多个线程共享的票源
    private static int ticket = 50;
    private  int ticket2=50;
    //设置线程任务:卖票
    @Override
    public void run() {
        System.out.println("this:"+this);
        //使用死循环,让卖票操作重复执行
        while(true){
            payTicketStatic();
            //payTicket();
        }
    }
    /*
        静态的同步方法
        锁对象是谁?
        不能是this
        this是创建对象之后产生的,静态方法优先于对象
        静态方法的锁对象是本类的class属性-->class文件对象(反射)
     */
   /* public static *//*synchronized*//* void payTicketStatic(){
        synchronized (RunnableImpl.class){
            //先判断票是否存在
            if(ticket>0){
                //提高安全问题出现的概率,让程序睡眠
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //票存在,卖票 ticket--
                System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                ticket--;
            }
        }
    }*/
    public static synchronized void payTicketStatic() {
        //先判断票是否存在
        if (ticket > 0) {
            //票存在,卖票 ticket--
            System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");
            ticket--;
            //提高安全问题出现的概率,让程序睡眠
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    /*
        定义一个同步方法
        同步方法也会把方法内部的代码锁住
        只让一个线程执行
        同步方法的锁对象是谁?
        就是实现类对象 new RunnableImpl()
        也是就是this
     */
    /*public *//*synchronized*//* void payTicket(){
        synchronized (this){
            //先判断票是否存在
            if(ticket>0){
                //提高安全问题出现的概率,让程序睡眠
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //票存在,卖票 ticket--
                System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                ticket--;
            }
        }
    }*/
    public synchronized void payTicket() {
        //先判断票是否存在
        if (ticket2 > 0) {
            //提高安全问题出现的概率,让程序睡眠
            //票存在,卖票 ticket--
            System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket2 + "张票");
            ticket2--;
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Test class

public class Demo01Ticket {
    public static void main(String[] args) {
       // Runnable runnable=new RunnableImpl();
        //创建Thread类对象,构造方法中传递Runnable接口的实现类对象
        Thread t0 = new Thread(new RunnableImpl(),"窗口一");
        Thread t1 = new Thread(new RunnableImpl(),"窗口二");
        Thread t2 = new Thread(new RunnableImpl(),"窗口三");
        //调用start方法开启多线程
        t0.start();
        t1.start();
        t2.start();
    }
}

Insert picture description here
It should be noted here that the method of synchronization lock object is a static method of the class (ie RunnableImpl.class), while the ordinary synchronization method of locking object is the object itself . The following illustrates the difference between the two.
Insert picture description here
The difference between the static synchronization method and the synchronization method can be reflected from the above figure.

lock

The lock lock is one of the other important synchronization mechanisms. To use a lock, you first need to wear a Lock object new ReentrantLock(), and then use the member methods lock() and unlock() of the lock object to clamp the code to solve the problem. The thread safety of the clip code,

public class RunnableImpl implements Runnable{
    //定义一个多个线程共享的票源
    private  int ticket = 1000;
    //1.在成员位置创建一个ReentrantLock对象
    Lock l = new ReentrantLock();
    //设置线程任务:卖票
    @Override
    public void run() {
        //使用死循环,让卖票操作重复执行
        while(true){
            //2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
            l.lock();
            //先判断票是否存在
            if(ticket>0){
                //提高安全问题出现的概率,让程序睡眠
                try {
                    Thread.sleep(10);
                    //票存在,卖票 ticket--
                    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁
                    l.unlock();//无论程序是否异常,都会把锁释放
                }
            }
        }
    }
    /*//设置线程任务:卖票
    @Override
    public void run() {
        //使用死循环,让卖票操作重复执行
        while(true){
           //2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
           l.lock();
            //先判断票是否存在
            if(ticket>0){
                //提高安全问题出现的概率,让程序睡眠
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //票存在,卖票 ticket--
                System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                ticket--;
            }
            //3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁
            l.unlock();
        }
    }*/
}

Test class

public class Demo01Ticket {
    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        RunnableImpl run = new RunnableImpl();
        //创建Thread类对象,构造方法中传递Runnable接口的实现类对象
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //调用start方法开启多线程
        t0.start();
        t1.start();
        t2.start();
    }
}

Operation results The
Insert picture description here
Insert picture description here
operation achieved the expected results of the case.

Message communication mechanism

The message passing method adopts direct communication between threads, and different threads achieve the purpose of interaction by sending messages explicitly. The most famous way of message passing should be the actor model. In this model, everything is an actor, and communication between all actors must be achieved by passing messages. Every actor has an inbox (message queue) to store messages received from other actors. Actors can also send messages to themselves. Of course, this situation is quite special, and price comparisons are rare.

Insert picture description here

Wait/notify mechanism

In Java, Wait/Notify (NotifyAll) is a very common message communication mechanism. This mechanism is a bit like the interrupt mechanism in embedded. The following will focus on the case. The requirements of the case are as follows: There is an interrupt, interrupt handler , CPU has three roles. When an interrupt is initiated, it is first processed by the interrupt processor. If it is a non-maskable interrupt, it will be directly handled by the cpu. If it is a maskable interrupt, it will be processed by the interrupt processor first, and then by the cpu. Simply simulate this process with the code, the case code is as follows.
Interrupt class

public class Interruption {
    private String interruptType;
    private String treatment;
    private boolean interruptFlag=false;

    public Interruption(String interruptType, String treatment, boolean interruptFlag) {
        this.interruptType = interruptType;
        this.treatment = treatment;
        this.interruptFlag = interruptFlag;
    }

    public Interruption(String interruptType) {
        this.interruptType = interruptType;
    }

    public Interruption() {
    }

    public String getInterruptType() {
        return interruptType;
    }

    public void setInterruptType(String interruptType) {
        this.interruptType = interruptType;
    }

    public String getTreatment() {
        return treatment;
    }
    public void setTreatment(String treatment) {
        this.treatment = treatment;
    }
    public boolean isInterruptFlag() {
        return interruptFlag;
    }
    public void setInterruptFlag(boolean interruptFlag) {
        this.interruptFlag = interruptFlag;

    }
    @Override
    public String toString() {
        return "Interruption{" +
                "interruptType='" + interruptType + '\'' +
                ", treatment='" + treatment + '\'' +
                ", interruptFlag=" + interruptFlag +
                '}';
    }
}

Interrupt handler

//extends thread
public class InterruptHandler extends Thread{
    private Interruption interruption;
    public InterruptHandler(Interruption interruption,String name) {
        super(name);
        this.interruption = interruption;
    }

    public InterruptHandler(Interruption interruption) {
        this.interruption = interruption;
    }

    @Override
    public void run(){
        int count =0;
        //模拟总中断开关寄存器相关动作
        while (true){
            synchronized (interruption){
                //now there are some interrupt message in interruptHandler
                if(interruption.isInterruptFlag()){
                    try {
                        interruption.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //interruptHandler is empty
                System.out.println("interruptHandler is empty,start produce some interrupt");
                if(count%2==0){
                    interruption.setInterruptType("MI interruption");
                    interruption.setTreatment("response delay");
                }else {
                    interruption.setInterruptType("NMI interruption");
                    interruption.setTreatment("response immediately");
                }
                count++;
                System.out.println(interruption.getInterruptType()+"is readyCPU processing should be :" +
                        interruption.getTreatment());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                interruption.setInterruptFlag(true);
                interruption.notify();
            }
        }
    }
}

CPU type

public class CPU implements Runnable{
    private Interruption interruption;
    private  String threadName;

    public CPU(Interruption interruption, String threadName) {
        this.interruption = interruption;
        this.threadName = threadName;
    }

    public CPU(Interruption interruption) {
        this.interruption = interruption;
    }

    @Override
    public void run() {
        while (true){
            synchronized (interruption){
                if(!interruption.isInterruptFlag()){
                    try {
                        interruption.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("CPU is processing"+interruption.getInterruptType()+"and will"+
                        interruption.getTreatment());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("finished");
                System.out.println("----------------------------------------");
                interruption.setInterruptFlag(false);
                interruption.notify();
            }
        }
    }
}

Test class

public class DemoTest {
    public static void main(String[] args) {
        Interruption interruption = new Interruption();
        InterruptHandler interruptHandler = new InterruptHandler(interruption,"interruptionHandler");
        interruptHandler.start();

        CPU cpu = new CPU(interruption);
        new Thread(cpu,"cpu").start();
    }
}

Operation results The
Insert picture description here
operation achieved the expected results of the case.

Pipeline communication mechanism

Case

The message maker A needs to generate a message and put the message in the pipeline queue, and then print the message put in the queue. The message consumer extracts the message in the pipeline queue and prints the extracted message to the console.

method one

Through PipedInputStream and PipedOutputStream to realize the communication between threads, the ThreadWrite thread generates the message and puts it in the queue first, and then the ThreadRead thread consumes the message, directly on the code.
WriteData class

public class WriteData {
    public void writeMethod(PipedOutputStream out){
        try {
            System.out.println("write :");
            int maxSize =50;
            StringBuffer outData1=new StringBuffer();
            String outData =null;
            for(int i=0;i<maxSize;i++){
                outData=""+(i+1);
                out.write(outData.getBytes());
                if(i==0){
                    outData1.append("["+(i+1)+",");
                }else if(i==maxSize-1){
                    outData1.append(i+1+ "]"+"\n");
                }else {
                    if((i+1)%5==0){

                        outData1.append(i+1+"]"+"\n");
                        outData1.append("[");
                    }else {
                        outData1.append(i+1+ ",");
                    }
                }
            }
            String s = outData1.toString();
            System.out.println(s);
            System.out.println();
            out.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

ReadData类

public class ReadData {
    public void readMethod(PipedInputStream inputStream){
        try {
            System.out.println("read:");
            byte[] byteArray=new byte[128];
            int readLength = inputStream.read(byteArray);
            while (readLength != -1){
                String newData = new String(byteArray, 0, readLength);
                System.out.println(newData);
                readLength=inputStream.read(byteArray);
            }
            System.out.println();
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ThreadWrite类

public class ThreadWrite implements Runnable{

    WriteData writeData;
    PipedOutputStream outputStream;

    public ThreadWrite(WriteData writeData,PipedOutputStream outputStream){
        this.writeData = writeData;
        this.outputStream = outputStream;
    }

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

ThreadRead

public class ThreadRead extends Thread{
    ReadData readData;
    PipedInputStream inputStream;

    public ThreadRead(ReadData readData, PipedInputStream inputStream) {
        this.readData = readData;
        this.inputStream = inputStream;
    }

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

Test class

public class TestDemo1 {
    public static void main(String[] args) {
        try {
            WriteData writeData=new WriteData();
            ReadData readData=new ReadData();
            PipedInputStream input=new PipedInputStream();
            PipedOutputStream out=new PipedOutputStream();
            out.connect(input);
            ThreadRead threadRead=new ThreadRead(readData, input);
            threadRead.start();
            Thread.sleep(2000);
            ThreadWrite threadWriteImpl=new ThreadWrite(writeData, out);
            Thread threadWrite = new Thread(threadWriteImpl,"threadWrite");
            threadWrite.start();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Test result The
Insert picture description here
test result is perfect.

Method Two

Case 2 uses PipedReader and PipedWriter classes for pipe communication. The essential difference between method 2 and method is the difference between InputStream, OutputStrean and Reader and Writer. The code is implemented as follows.
WriteData class

public class WriteData {
    public void writeData(PipedWriter writer){
        int maxSize =50;
        String outData=null;
        StringBuffer outData1= new StringBuffer();
        System.out.println("write:");
        try {
            for (int i = 0; i < maxSize; i++) {
                outData=""+(i+1);
                writer.write(outData);
                if(i==0){
                    outData1.append("["+(i+1)+",");
                }else if(i==maxSize-1){
                    outData1.append(i+1+"]"+"\n");
                }else {
                    if((i+1)%5==0){
                        outData1.append(i+1+"]"+"\n");
                    }else {
                        outData1.append(i+1+",");
                    }
                }
            }
            String s = outData1.toString();
            System.out.println(s);
            writer.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

ReadData类

public class ReadData {
    public void readMethod(PipedReader read){
        try {
            char [] byteArray = new char[64];
            int readLength = read.read(byteArray);
            System.out.println("read:");
            while (readLength !=-1){
                String newData = new String(byteArray, 0, readLength);
                System.out.print(newData);
                readLength = read.read(byteArray);
            }
            System.out.println();
            read.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ThreadWriter class

public class ThreadWriter extends Thread {
    WriteData out;
    PipedWriter writer;
    public ThreadWriter(WriteData out, PipedWriter writer) {
        this.out = out;
        this.writer = writer;
    }
    @Override
    public void run() {
        out.writeData(writer);
    }
}

Test class

public class DemoTest2 {
    public static void main(String[] args) {
        try {
            WriteData writeData = new WriteData();
            ReadData readData = new ReadData();
            PipedWriter pipedWriter = new PipedWriter();
            PipedReader pipedReader = new PipedReader();
            pipedWriter.connect(pipedReader);
            ThreadWriter threadWriter = new ThreadWriter(writeData,pipedWriter);
            threadWriter.start();
            Thread.sleep(2000);
            ThreadReader threadReader = new ThreadReader(readData, pipedReader);
            Thread threadReader1 = new Thread(threadReader, "threadReader");
            threadReader1.start();
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
    }
}

Through the comparison of method 1 and method 2, it is found that the two methods are basically the same. The biggest difference lies in the way the message producer puts the message into the pipeline queue. The results are as follows.
Insert picture description here
PipeOutputStream needs to convert the written object to binary before writing to the pipeline queue, while PipedWriter does not need to convert, just write directly.
Test Results:
Insert picture description here

to sum up

In short, the communication between multiple threads can be divided into two mechanisms, memory sharing mechanism and message passing mechanism. Among the memory sharing mechanisms, there are common synchronization mechanisms and polling mechanisms, while synchronization mechanisms and synchronization codes are common. Blocks, locks; and the common message delivery mechanisms are waiting/notification mechanisms and pipeline mechanisms. These communication methods have their own application scenarios, which makes multi-threaded communication more colorful and complete. Xiao Yuan hereby asks you all Correct criticism.

Guess you like

Origin blog.csdn.net/xueshanfeitian/article/details/106558880
Recommended