多线程核心技术-线程间通信

1.等待&通知(wait&notify)机制:

wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。

notify():方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()仅通知一个线程(notifyAll()可以通知同一个共享资源的全部线程)

ThreadA

public class ThreadA extends Thread {
 
    private Object lock;
 
    public ThreadA(Object lock) {
        this.lock = lock;
    }
 
    @Override
    public void run() {
        try {
            synchronized (lock) {
                System.out.println("准备wait");
                lock.wait();
                System.out.println("wait结束");
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

ThreadB

public class ThreadB extends Thread{
 
    private Object lock;
 
    public ThreadB(Object lock) {
        this.lock = lock;
    }
 
    @Override
    public void run() {
        synchronized (lock) {
            System.out.println("开始执行notify");
            lock.notify();
            System.out.println("notify执行完毕");
        }
    }
}

运行类

public class Run {
 
    public static void main(String[] args) {
        String lock = new String("lock");
        ThreadA threadA = new ThreadA(lock);
        threadA.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ThreadB threadB = new ThreadB(lock);
        threadB.start();
 
    }
}

这里要注意几点:

1)等待和唤醒一定要在synchronized代码块中执行,否则会报IllegalMonitorStateException

2)线程执行完wait会立刻释放锁,执行完notify并不会立刻释放锁,而是要等执行notify线程走出synchronized代码块才会释放(sleep方法同样不释放锁)

PS:wait(long):带参数的wait方法会在时间内等待唤醒,如果超过时间则自动唤醒

2.通过管道进行线程间通信:字节流

(1)PipeInputStream和PipeOutputStream

(2)PipeReader和PipeWriter

创建ReadData类


public class ReadData {
 
    public void readMethod(PipedInputStream input){
        try{
            System.out.println("read :");
            byte[] byteArray = new byte[20];
            int readLenth = input.read(byteArray);
            while ( readLenth != -1){
                String newData = new String(byteArray,0,readLenth);
                System.out.print(newData);
                readLenth = input.read(byteArray);
            }
            System.out.println();
            input.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
WriteData类
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.print(outData);
            }
            System.out.println();
            out.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

ThreadRead类

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

ThreadWrite类

public class ThreadWrite extends Thread {
 
    private WriteData write;
    private PipedOutputStream out;
 
    public ThreadWrite(WriteData write, PipedOutputStream out) {
        super();
        this.write = write;
        this.out = out;
    }
 
    @Override
    public void run() {
        write.writeMethod(out);
    }
}
运行Run类
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();
 
//            pipedInputStream.connect(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();
        }
    }
}

运行结果

 

inputStream.connect(outputStream)或者outputStream.connect(inputStream)的作用使两个Stream之间产生通信链接,这样才可以将数据进行输出与写入

同理PipeReader和PipeWriter一模一样

3.join的使用

join的作用是:等待线程销毁,或者说join是使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码

方法join具有使线程排队运行的作用,与synchronized的区别是join在内部使用wait()方法进行等待,而synchronized关键字使用的是对象监视器原理作为同步

线程join和intercept相遇,同样会抛出InterceptedException异常(凡是方法使用时候需要抛出这个异常的 一般都会和intercept冲突,例如sleep),代码如下

ThreadA

public class ThreadA extends Thread {
    @Override
    public void run() {
        for(;;){
            //我什么也不做,静静看着你俩打
        }
    }
}

ThreadB

public class ThreadB extends Thread {
    @Override
    public void run() {
        try{
            ThreadA a = new ThreadA();
            a.start();
            a.join();
            System.out.println("B要等A完事儿在打印");
        }catch (InterruptedException e){
            System.out.println("B发现出事儿了");
            e.printStackTrace();
        }
    }
}

ThreadC

public class ThreadC extends ThreadA {
    private ThreadB threadB;
 
    public ThreadC(ThreadB threadB) {
        super();
        this.threadB = threadB;
    }
 
    @Override
    public void run() {
        threadB.interrupt();
    }
}

Run类

public class Run {
    public static void main(String[] args) {
        try{
            ThreadB threadB = new ThreadB();
            threadB.start();
            Thread.sleep(500);
            ThreadC threadC = new ThreadC(threadB);
            threadC.start();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

此时运行会抛出InterruptedException异常

join(long)的使用

join(long)的效果和sleep(long)一样,区别是join(long)内部是wait(long)方法实现的,所以join(long)方法具有释放锁的特点,而sleep(long)不具备此效果,可以通过查看源码来证实

也因为join(long)会释放锁,所以可能会导致join后面的代码先执行,出现意外

4.ThreadLocal的使用

ThreadLocal为每个线程绑定自己的值,存放每个线程的私有数据,具有隔离性

InheritableThreadLocal具有值继承,值继承再修改特性





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值