Java典型线程通讯方式

等待\通知机制

  • 如果不使用等待\通知机制,当线程1要向线程2实现线程通讯,可以通过共享一个变量,线程2可以使用while不停地对某一条件进行检测,直到线程1对其进行了修改(从而使条件满足),就实现了一次线程1到线程2的通讯,不过这样将浪费CPU的资源。

实现

  • wait()方法:

    • Object类的一个方法,该方法将当前线程置入预执行队列中,并且在wait()代码处停止执行,直到接受到通知来或被中断为止。
    • 在调用wait()方法之前,线程必须获得该对象的对象级别锁。否则抛出IllegalMonitorStateException,它是RuntimeException的一个子类,不需要捕捉异常。
    • 执行wait()方法之后,当前线程释放锁。
    • wait(long):如果wait方法在long时间内没有被通知,那么超过这个时间则自动唤醒。
  • notify()/notifyAll()方法:

    • Object类的一个方法,该方法用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程,则由线程规划随机挑选出一个呈wait状态的线程对它发出通知notify,并使它等待获取该对象的对象锁。(notifyAll将通知持有该对象的所有其他线程)
    • 调用notify()方法前,线程必须获得该对象的对象级别锁。否则抛出IllegalMonitorStateException。
    • 执行notify()之后,当前线程并不会马上释放该对象锁,呈wait状态的线程也不能马上获取该锁。在等到执行notify()的方法将程序执行完,也就是退出synchronized代码块后,才会开始上述过程。

管道流

示例:

要点

在Java语言中提供了各种各样的输入、输出流,其中管道流(PipeStream)是一种特殊的流,用于在不同线程间直接传送数据。

Java IO中的管道为运行在同一个JVM中的两个线程提供了通信的能力。所以管道也可以作为数据源以及目标媒介。

你不能利用管道与不同的JVM中的线程通信(不同的进程)。在概念上,Java的管道不同于Unix/Linux系统中的管道。在Unix/Linux中,运行在不同地址空间的两个进程可以通过管道通信。在Java中,通信的双方应该是运行在同一进程中的不同线程。

可以通过Java IO中的PipedOutputStreamPipedInputStream创建管道。一个PipedInputStream流应该和一个PipedOutputStream流相关联。一个线程通过PipedOutputStream写入的数据可以被另一个线程通过相关联的PipedInputStream读取出来。PipedReaderPipedWriter同理。

join方法

示例:

class TestThread implements Runnable{
    public void run(){
        System.out.println("TestThread");
    }
}

public class Test{
    public static void main(String[] args){
        try{
            TestThread testThread = new TestThread();
            testThread.start();
            testThread.join();
            System.out.println("Main");
        } catch (InterruptedException e{
        e.printStackTrace();
    }
}

结果:
TestThread
Main

要点

  • 方法join的作用是使被调用的线程对象正常执行run()方法中的任务,而调用线程将进行无限期的阻塞直到被调用线程被销毁后,才执行后面的代码。
  • 换一种思考方式,方法join具有使线程排队运行的作用,有些类似于同步的运行效果。
  • join()方法执行过程中,如果被执行线程遇到interrupt()方法,那么将会抛出InterruptedException异常。
  • join(long):如果被执行方法在long时间内依旧没有被销毁,那么超过这个时间从join方法中返回执行后面的代码。方法join(long)的功能在内部是通过wait(long)实现的,所以也具有释放锁的特点。

类InheritableThreadLocal的使用

示例:

public class ThreadLocalParentSon {
       //public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
       public static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<Integer>();
       static class MyThread extends Thread{
            @Override
            public void run(){
                System.out.println("Son Thread = " + threadLocal.get());
            }
       }
       public static void main(String[] args) {
             threadLocal.set(new Integer(127));// 当前线程设置值
             Thread thread = new MyThread();
             thread.start();
             System.out.println("Main Tread = " + threadLocal.get());
       }
}

Main Tread = 127
Son Thread = 127

若没有使用 InheritableThreadLocal 之前的输出结果:
Main Tread = 127
Son Thread = null

要点

  • 使用InheritableTreadLocal类可以让子线程从父线程中取得值。
  • 需要注意的一点是,如果子线程在取得值得同时,主线程将InheritableThreadLocal中的值进行修改,那么子线程取到的值还是旧值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值