线程直接的通信:通过管道流进行简单的交互
public class ThreadDemo6 {
public static void main(String[] args) {
PipedOutputStream pos=null;
PipedInputStream pis=null;
try {
pos=new PipedOutputStream();
pis=new PipedInputStream(pos);
} catch (IOException e) {
e.printStackTrace();
}
Sender sender=new Sender(pos);
Thread t1=new Thread(sender);
Receiver receiver=new Receiver(pis);
Thread t2=new Thread(receiver);
t1.start();
t2.start();
}
}
class Sender implements Runnable {
private OutputStream out;
public Sender(OutputStream out) {
super();
this.out = out;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
byte value = (byte) (Math.random() * 100);
System.out.println("send value is " + value);
try {
out.write(value);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Receiver implements Runnable {
private InputStream in;
public Receiver(InputStream in) {
super();
this.in = in;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
try {
byte value = (byte) in.read();
System.out.println("receiver value is " + value);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
有一个弊端就是在所有的数据写完后才能去读取,这样在写的时候一直占用内存,我们希望每写一点就能拿一点。看下边的实现:
线程直接的通信:使用Thread.yield()模拟一个生产者和消费者的模型
* 效率还是比较差。yield方法是主动放弃了cpu,又去竞争。
public class ThreadDemo7 {
public static void main(String[] args) {
FlagSend flagSend = new FlagSend();
FlagRec flagRec = new FlagRec(flagSend);
Thread t1 = new Thread(flagSend);
Thread t2 = new Thread(flagRec);
t1.start();
t2.start();
}
}
class FlagSend implements Runnable {
int theValue;
boolean flag;//是否有食物:true有食物
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
while (flag) {
Thread.yield();
}
theValue = new Random().nextInt(1000);// 制造食物
System.out.println("send value is " + theValue);
flag = true;// 等待食客去吃
}
}
}
class FlagRec implements Runnable {
public FlagRec(FlagSend flagSend) {
super();
this.flagSend = flagSend;
}
private FlagSend flagSend;
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
while (!flagSend.flag) {
Thread.yield();
}
System.out.println("receiver value is " + flagSend.theValue);
flagSend.flag = false;
}
}
}
yield方法是主动放弃了cpu,又去竞争。效率比较差,接收的人不知道是否send已经Ok了。我们希望我们发送以后就去提醒接收者去拿不是一直去在放弃。
线程直接的通信:wait/notify 任何一个对象都拥有一个线程等待池
* 挂在同一个对象的线程等待池中的线程之间可以互相唤醒 wait/notify是属于Object类的
* wait方法必须放入synchronized同步块中
/**
* @author Janle
*
*/
public class ThreadDemo8 {
public static void main(String[] args) {
Cooker cooker=new Cooker();
Diners diners=new Diners(cooker);
Thread t1=new Thread(cooker);
Thread t2=new Thread(diners);
//当程序只有守护线程时候程序退出。
t2.setDaemon(true);
t1.start();
t2.start();
}
}
class Cooker implements Runnable {
boolean hasFood;
int value;
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
// 将锁挂到同一个线程等待池中
synchronized (this) {
try {
while (hasFood) {// 使用while是因为存在虚假唤醒,不能使用if
/**
* 在没有被通知、中断或超时的情况下,线程还可以唤醒一个所谓的虚假唤醒 (spurious wakeup)。
* 虽然这种情况在实践中很少发生,但是应用程序必须通过以下方式防止其发生,
* 即对应该导致该线程被提醒的条件进行测试, 如果不满足该条件,则继续等待。换句话说,等待应总是发生在循环中
*/
this.wait();//wait方法会释放钥匙
}
} catch (InterruptedException e) {
e.printStackTrace();
}
value = new Random().nextInt(1000);
System.out.println("Cooker 生产食物 " + value);
hasFood=true;
this.notify();
}
}
}
}
class Diners implements Runnable {
private Cooker cooker;
public Diners(Cooker cooker) {
super();
this.cooker = cooker;
}
@Override
public void run() {
for (;;) {
// 将锁挂到同一个线程等待池中
synchronized (cooker) {
try {
while(!cooker.hasFood){
cooker.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Diners 消费食物 " + cooker.value);
cooker.hasFood=false;
cooker.notify();
}
}
}
}
线程中的通讯:在实际的业务中的使用
public class ThreadDemo9 {
public static void main(String[] args) {
final Bussiness bus=new Bussiness();
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
bus.send();
}
});
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
bus.recived();
}
});t2.setDaemon(true);
t1.start();
t2.start();
}
}
class Bussiness {
boolean flag;
int value;
public void send() {
for (int i = 0; i < 5; i++) {
synchronized (this) {
try {
while (flag) {
this.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
value = new Random().nextInt(1000);
System.out.println("send value is " + value);
flag = true;
this.notify();
}
}
}
public void recived() {
while (true) {
synchronized (this) {
try {
while (!flag) {
this.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("receive value is " + value);
flag = false;
this.notify();
}
}
}
}