所谓线程间的通信,无非就是线程之间相互协作,互相影响,数据交互。
1、不使用wait和notify
两个线程在不使用wait 和 notify的前提下,也能通过sleep和while来实现相互影响。两个线程对同一个变量做操作,并循环监控这个变量。
2、wait()和notify()
Wait()
方法wait() 的作用是使当前执行代码的线程进程等待,wait()是Object类的方法,该方法用来将当前线程置入“预执行队列”,并在wait()所在的代码行处停止执行,知道接到通知或者被中断为止。
在调用前线程必须获得该对象的对象级的锁,即只能在同步方法或者同步块中调用wait()方法。
执行wait后,当前线程释放锁,在从wait返回前,该线程与其他线程竞争重新获得锁。如果调用wait时没有适当的锁,则抛出异常, 因此不需要用try-catch语句进行异常捕获。
notify()
该方法用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选出其中一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁。
在执行notify时,当前线程不会马上释放锁,wait的线程也不能马上得到锁,需要等notify的线程执行完,也就是退出synchronized代码块后,才会释放锁。
notify在调用前线程必须获得该对象的对象级的锁,即只能在同步方法或者同步块中调用。
wait使线程停止运行,notify使停止的线程继续运行。
示例代码:
public class MyThread1 extends Thread {
private Object lock;
public MyThread1(Object lock) {
super();
this.lock = lock;
}
@Override
public void run() {
try {
synchronized (lock) {
System.out.println("开始 wait time=" + System.currentTimeMillis());
lock.wait();
System.out.println("结束 wait time=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class MyThread2 extends Thread {
private Object lock;
public MyThread2(Object lock) {
super();
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
System.out.println("开始 notify time=" + System.currentTimeMillis());
lock.notify();
System.out.println("结束 notify time=" + System.currentTimeMillis());
}
}
}
import extthread.MyThread1;
import extthread.MyThread2;
public class Test {
public static void main(String[] args) {
try {
Object lock = new Object();
MyThread1 t1 = new MyThread1(lock);
t1.start();
Thread.sleep(3000);
MyThread2 t2 = new MyThread2(lock);
t2.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
wait 方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒。
notify 方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待推列,进入运行状态,也就是说notify只通知一个线程,而被通知的线程是随机的。
notifyAll() 可以使所有正在等待队列中等待同一共享资源的全部线程,从等待状态退出,进入运行状态。此时,优先级最高的那个线程最先执行,也可能是随即执行,这要取决于JVM虚拟机的实现。
锁释放的情况:1、执行完同步代码块和方法,就会释放对象锁。
2、 实行同步代码块的过程中,遇到异常导致线程终止,锁也会被释放。
3、在执行同步代码块中,执行了wait方法,就会释放锁,该线程也很贵进入线程等待池,等待被唤醒。
3、Wait(long)和通知过早
wait(long) 等待某一段时间是否有线程对锁进行唤醒,如果超过这个时间则自动唤醒。
通知过早:nodify在wait之前运行,wait永远不能被唤醒。
示例代码:
package test;
public class MyRun {
private String lock = new String("");
private boolean isFirstRunB = false;
private Runnable runnableA = new Runnable() {
@Override
public void run() {
try {
synchronized (lock) {
while (isFirstRunB == false) {
System.out.println("begin wait");
lock.wait();
System.out.println("end wait");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
private Runnable runnableB = new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("begin notify");
lock.notify();
System.out.println("end notify");
isFirstRunB = true;
}
}
};
public static void main(String[] args) throws InterruptedException {
MyRun run = new MyRun();
Thread a = new Thread(run.runnableA);
a.start();
Thread.sleep(100);
Thread b = new Thread(run.runnableB);
b.start();
}
}
4、管道通信
管道流是一种特殊的流,用于在不同线程之间传送数据。一个线程发送数据到输出管道,另一个线程中管道中读取数据。通过管道,实现不同线程减的通信。
- PipedInputStream和PipedOutputStream 字节流
- PipedReader和PipedWriter 字符流
- 字节流示例代码:
import java.io.PipedInputStream;
import service.ReadData;
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;
import service.WriteData;
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);
}
}
import java.io.IOException;
import java.io.PipedInputStream;
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.print(newData);
readLength = input.read(byteArray);
}
System.out.println();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.IOException;
import java.io.PipedOutputStream;
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();
}
}
}
public static void main(String[] args) {
try {
WriteData writeData = new WriteData();
ReadData readData = new ReadData();
PipedInputStream inputStream = new PipedInputStream();
PipedOutputStream outputStream = new PipedOutputStream();
// inputStream.connect(outputStream);
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();
}
}
}
- 字符流示例代码:
import java.io.PipedReader;
import service.ReadData;
public class ThreadRead extends Thread {
private ReadData read;
private PipedReader input;
public ThreadRead(ReadData read, PipedReader input) {
super();
this.read = read;
this.input = input;
}
@Override
public void run() {
read.readMethod(input);
}
}
import java.io.PipedWriter;
import service.WriteData;
public class ThreadWrite extends Thread {
private WriteData write;
private PipedWriter out;
public ThreadWrite(WriteData write, PipedWriter out) {
super();
this.write = write;
this.out = out;
}
@Override
public void run() {
write.writeMethod(out);
}
}
public class ReadData {
public void readMethod(PipedReader input) {
try {
System.out.println("read :");
char[] byteArray = new char[20];
int readLength = input.read(byteArray);
while (readLength != -1) {
String newData = new String(byteArray, 0, readLength);
System.out.print(newData);
readLength = input.read(byteArray);
}
System.out.println();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.IOException;
import java.io.PipedWriter;
public class WriteData {
public void writeMethod(PipedWriter out) {
try {
System.out.println("write :");
for (int i = 0; i < 300; i++) {
String outData = "" + (i + 1);
out.write(outData);
System.out.print(outData);
}
System.out.println();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import extthread.ThreadRead;
import extthread.ThreadWrite;
import service.ReadData;
import service.WriteData;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
public class Run {
public static void main(String[] args) {
try {
WriteData writeData = new WriteData();
ReadData readData = new ReadData();
PipedReader pipedReader = new PipedReader();
PipedWriter pipedWriter = new PipedWriter();
// inputStream.connect(outputStream);
pipedWriter.connect(pipedReader);
ThreadRead threadRead = new ThreadRead(readData, pipedReader);
threadRead.start();
Thread.sleep(2000);
ThreadWrite threadWrite = new ThreadWrite(writeData, pipedWriter);
threadWrite.start();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果: