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();
        }
    }
}
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();
        }
    }
}
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);
    }
}
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);
    }
}
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();
        }
    }
}

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


实现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()实现对继承的值进行加工

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值