并发编程(九)java线程间的通信方式

156 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

1.java线程间的通信方式

今天先简单说一下,以后会详细讲述。

1. volitate 、synchronize、lock。(都保证可见性)

2. wait、notify、await() 、 signal

3. 管道输入、输出流 (示例代码:PipeInOut.java)

管道输入/输出流和普通的文件输入/输出流或者网络输入/输出流不同之处在于,它主要用于线程之间的数据传输,而传输的媒介为内存。 管道输入/输出流主要包括了如下4种具体实现:PipedOutputStream、PipedInputStream、PipedReader和PipedWriter,前两种面向字节,而后两种面向字符。

4. Thread.join() : 隐式唤醒。等待其他线程执行完成,其他线程会发送唤醒信号。

5. ThradLocal() ---》支持子线程继承的一种形式。埋点。

6. 线程中断

这里我们就说一下第三点和第6点,前1/2/5点以后会详细讲解。

2简单说一下管道输入、输出流

这个不是重点,大概了解一下即可。

public class PipeInOut {
    public static void main(String[] args) throws IOException {
        PipedWriter out = new PipedWriter();
        PipedReader in = new PipedReader();
        // 将输出流和输入流进行连接,否则在使用时会抛出IOException
        out.connect(in);
        Thread printThread = new Thread(new Print(in), "PrintThread");
        printThread.start();
        int receive = 0;
        try {
            while ((receive = System.in.read()) != -1) {
                out.write(receive);
            }
        } finally {
            out.close();
        }
    }
    static class Print implements Runnable {
        private PipedReader in;
        public Print(PipedReader in) {
            this.in = in;
        }
        public void run() {
            int receive = 0;
            try {
                while ((receive = in.read()) != -1) {
                    System.out.print((char) receive);
                }
            } catch (IOException ex) {
            }
        }
    }
}

我们可以看到效果如下,我输入一个Hello,程序也跟着输入一个Hello,程序把输入的给了主线程的receive变量,out再调用write,然后到了另一个线程去调用in的read()方法去读取这个write的东西。

image.png

3线程中断

我下面贴上示例代码,可能有点长,但是很简单:

public class ThreadInterrupted {
    public static void main(String[] args) throws InterruptedException {
        // sleepThread不停的尝试睡眠
        Thread sleepThread = new Thread(new SleepRunner(), "SleepThread");
        sleepThread.setDaemon(true);
        Thread busyThread = new Thread(new BusyRunner(), "BusyThread");
        busyThread.setDaemon(true);
        sleepThread.start();
        busyThread.start();
        // 休眠5秒,让sleepThread和busyThread充分运行
        TimeUnit.SECONDS.sleep(5);
        sleepThread.interrupt();
        busyThread.interrupt();
        //sleep方法响应中断,肯定会中断sleep。在抛出异常之前,会清理掉我们的 中断标志。 会返回false,因为当前线程已经停止了。
        System.out.println("SleepThread interrupted is " + sleepThread.isInterrupted());

        // busy thread ,没有立即响应中断,知识他的中断标志位 显示 被中断,这个是isInterrupted会返回true。
        System.out.println("BusyThread interrupted is " + busyThread.isInterrupted());
        // 防止sleepThread和busyThread立刻退出
        TimeUnit.SECONDS.sleep(5);
    }

    static class SleepRunner implements Runnable {
        @SneakyThrows
        @Override
        public void run() {
            while (true) {
                    // 先清除标志,后抛异常、(sleep)
                    TimeUnit.SECONDS.sleep(100);
            }
        }
    }
    static class BusyRunner implements Runnable {
        @Override
        public void run() {
            while (true) {
            }
        }
    }

}

我们可以看到效果如下:

image.png

线程中断总结来说还是两句话:

sleep方法响应中断,肯定会中断sleep。在抛出异常之前,会清理掉我们的 中断标志。 会返回false,因为当前线程已经停止了。

busy thread ,没有立即响应中断,知识他的中断标志位 显示 被中断,这个是isInterrupted会返回true。