线程间通信
目录
一、volatile 关键字
为什么volatile关键字可以?因为之前说过了,此关键字能保证变量的可见性,也就是说变量一旦被修改,立马能被其他线程所感知
例子如下:
private static volatile boolean flag=true;
private static void setFlag(){
flag=false;
}
public static void main(String[] args) {
new Thread(()->{
System.out.println("还没变");
while (flag){
// flag不改变 就一直死循环直至发现值改变
}
System.out.println("我感知到变化了");
}).start();
try {
//等待1s才执行下一个线程
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
setFlag();
System.out.println("我修改了");
}).start();
}
二、等待/通知机制
相关方法为:
- notify():通知一个在对象上等待的线程,使其从wait()方法返回,返回的前提是该线程获得了锁
- notifyAll():通知所有在该对象上等待的线程
- wait():调用该方法进入waiting状态并会释放锁,只有被其他线程通知或者中断才返回
- wait(long):超时等待一段时间,到时间了还没通知就返回
- wait(long,int):增加了超时时间单位的控制
例子如下:
public static Object flag=true;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
synchronized (flag){
System.out.println("线程1:进入等待");
try {
flag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1:从等待中归来");
}
}).start();
Thread.sleep(1000);
new Thread(()->{
synchronized (flag){
System.out.println("线程2:上面那个线程调用wait后会释放锁,所以到我啦");
flag.notify();
System.out.println("线程2:我把它唤醒了,但是它需要等我执行完释放掉锁才会返回");
}
}).start();
}
结果:
注意:这个使用需要配合synchronized使用
三、管道通信
管道输入流/输出流主要包括如下4个具体实现:
- PipedInputStream
- PipedOutputStream
- PipedReader
- PipedWriter
前两种面向字节,后两种面向字符
例子如下:
public static void main(String[] args) throws InterruptedException, IOException {
// 读为接收
PipedReader in = new PipedReader();
// 写为输出
PipedWriter out = new PipedWriter();
// 将管道输入和输出连接起来
out.connect(in);
new Thread(() -> {
int receive = 0;
while (true) {
try {
if (((receive = in.read()) != -1)) {
System.out.println("接收到了:"+receive);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
try {
// 这里输入,给那边接收
out.write(11111);
// 死循环防止输入端结束 管道断裂
while (true){}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
结果:
四、Thread.join
这个是干嘛呢?就是等待线程结束
假设线程A执行了threadB.join()语句,其含义是:当前线程A等待线程B执行结束后才返回。说白了就是等待其他线程执行后才执行
例子如下:
public static void main(String[] args) throws InterruptedException, IOException {
System.out.println("主线程:我开始执行啦");
Thread threadB = new Thread(() -> {
System.out.println("线程B:我开始执行啦");
System.out.println("线程B:我要睡会儿");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程B:我睡醒执行完了");
});
threadB.start();
System.out.println("主线程:我等待线程B执行完我再执行");
threadB.join();
System.out.println("主线程:线程B执行完了,到我执行了");
}
结果:主线程一定是最后才执行完的
但是如果把join注释掉,那么线程B一定是最后执行完的: