• java多线程-线程间通信


    wait/notify机制

    线程与线程之间不是独立个体,它们彼此是可以互相通信和协作的。


    不使用wait/notify机制实现线程间通信

    可以使用sleep()和while(true)死循环法来实现多个线程间的通信


    wait/notify机制


    wait/notify机制的原理

    拥有相同锁的线程才能实现该机制


    wait()方法的基本使用

    该方法是Object类的方法,仅限锁对象调用。


    完整实现wait/notify机制


    线程状态的切换

    new Thread()新建线程,调用start()方法到运行,调用stop()方法销毁。运行状态调用yield()出让cpu资源,调用suspend()、sleep()、wait()方法暂停线程,调用stop()、run()方法销毁。暂停状态调用resume()方法到运行,调用stop()方法销毁。


    wait()方法:立即释放锁


    sleep()方法:不释放锁


    notify()方法:不立即释放锁


    interrupt()方法遇到wait()方法

    线程调用wait()方法后再对该线程对象执行interrupt()方法会出现Interrupted-Exception异常。


    notify()方法:只通知一个线程

    每调用一次notify()方法,只通知一个线程进行唤醒,唤醒的顺序与执行wait()方法的顺序一致。


    notifyAll()方法:通知所有线程


    wait(long)方法的基本使用

    带一个参数的wait(long)方法的功能是等待某一时间内是否有线程对锁进行notify()通知唤醒,如果超过这个时间则线程自动唤醒,能继续向下运行的前提是再次持有锁。


    wait(long)方法自动向下运行需要重新持有锁

    必须有锁才能向下运行,否则一直等待,直到有锁为止。


    通知过早问题与解决方法

    新增一个变量来控制通知顺序,由通知线程管理。


    wait条件发生变化与使用while的必要性

    多线程会导致消费异常,需要使用while保证程序正确


    生产者/消费者模式的实现

    解决假死:使用notifyAll()方法通知所有的类


    通过管道进行线程间通信—字节流

    import java.io.PipedInputStream;
    
    /**
     * @author 29467
     * @date 2022/9/7 22:51
     */
    public class ReadData {
        public void readMethod(PipedInputStream input){
            try{
                System.out.println("read:");
                byte[] byteArray = new byte[20];
                int readLength = input.read(byteArray);
                while(readLength != -1){
                    String newData = new String(byteArray,0,readLength);
                    System.out.println(newData);
                    readLength = input.read(byteArray);
                }
                System.out.println();
                input.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    import java.io.IOException;
    import java.io.PipedOutputStream;
    
    /**
     * @author 29467
     * @date 2022/9/7 22:44
     */
    public class WriteData {
    
        public void writeMethod(PipedOutputStream out){
            try {
                System.out.println("write:");
                for(int i = 0; i<300;i++){
                    String outData = "" + (i+1);
                    out.write(outData.getBytes());
                    System.out.println(outData);
                }
                System.out.println();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    import java.io.PipedInputStream;
    
    /**
     * @author 29467
     * @date 2022/9/7 23:10
     */
    public class ThreadRead extends Thread{
        private ReadData read;
        private PipedInputStream input;
    
        public ThreadRead(ReadData read, PipedInputStream input) {
            super();
            this.read = read;
            this.input = input;
        }
    
        @Override
        public void run() {
            read.readMethod(input);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    import java.io.PipedOutputStream;
    
    /**
     * @author 29467
     * @date 2022/9/7 23:07
     */
    public class ThreadWrite extends Thread{
        private WriteData writeData;
        private PipedOutputStream out;
    
        public ThreadWrite(WriteData writeData, PipedOutputStream out){
            super();
            this.writeData = writeData;
            this.out = out;
        }
    
        @Override
        public void run() {
            writeData.writeMethod(out);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    import java.io.IOException;
    import java.io.PipedInputStream;
    import java.io.PipedOutputStream;
    
    /**
     * @author 29467
     * @date 2022/9/7 23:12
     */
    public class Run {
        public static void main(String[] args) {
            try{
                WriteData writeData = new WriteData();
                ReadData readData = new ReadData();
    
                PipedInputStream inputStream = new PipedInputStream();
                PipedOutputStream outputStream = new PipedOutputStream();
    
                outputStream.connect(inputStream);
    
                ThreadRead threadRead = new ThreadRead(readData,inputStream);
                threadRead.start();
    
                Thread.sleep(2000);
    
                ThreadWrite threadWrite = new ThreadWrite(writeData,outputStream);
                threadWrite.start();
            }catch (IOException e){
                e.printStackTrace();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    通过管道进行线程间通信—字符流


    实现wait/notify的交叉备份

    利用notifyAll()和volatile变量来实现交叉备份


    join()方法的使用

    他的作用是等待线程对象销毁,会使得当前线程暂停等待(内部是wait()方法)


    join()方法和interrupt()方法出现异常

    join()和interrupt()方法彼此遇到会出现异常,不论先后


    join(long)方法的使用

    参数用于设置等待的时间,不管x线程是否执行完毕,时间到了并且重新获得了锁,则当前线程会继续向后运行。如果没有重新获得锁,则一直在尝试,知道获得锁为止。


    join(long)方法与sleep(long)方法的区别

    join(long)方法的功能是在内部是使用wait(long)方法来进行实现的,所以join(long)方法具有释放锁的特点


    join()方法后面的代码提前运行—出现意外

    原因:线程run()方法的随机性


    join(long millis,int nanos)方法的使用

    参数为毫秒和纳秒


    ThreadLocal的使用

    一个ThreadLocal对象对应一个value


    get()方法与null

    如果ThreadLocal没有对应的value值则返回null,如果有值则get()方法返回对应的值。


    类ThreadLocal存取数据流程分析

    ThreadLocal将值存到ThreadLocalMap中


    验证线程变量的隔离性

    线程可以从ThreadLocal里取出自己的值,不能取出其他线程的值


    解决get()方法返回null的问题

    重写ThreadLocal的initialValue()方法,返回的值为默认值。


    类InheritableThreadLocal的使用

    使用该类可以使子线程继承父线程的值


    类ThreadLocal不能实现值继承

    要继承的话用类InheritableThreadLocal


    值继承特性在源代码中的执行流程

    详见源代码


    父线程有最新的值,子线程仍是旧值


    子线程有最新的值,父线程仍是旧值


    子线程可以感应对象属性值的变化


    重写childValue()实现对继承的值进行加工

  • 相关阅读:
    【智能优化算法】基于移动阻尼波算法求解单目标优化问题附matlab代码
    音乐转录(AMT)库Omnizart论文笔记及实践
    芒格-“永远不要有受害者心态”
    INTELlij IDEA编辑VUE项目
    Jira使用教程-不古出品
    mmdetection 用yolox训练自己的coco数据集
    元气森林推“有矿”,农夫山泉们跟着“卷”?
    spring6-IOC容器
    pytorch应用于MNIST手写字体识别
    由于执行触发器导致登录失败,错误号为17892的解决方案
  • 原文地址:https://blog.csdn.net/weixin_51343683/article/details/126744529