线程通信介绍
本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信
线程通信简单举例加实现
举例
例如:
生产线程和消费线程之间要进行沟通,不生产就不消费,生产一个,消费一个。
分析:
经过我们分析得知,生产和消费线程一直在互相抢占CPU执行权。
一会儿生产好几个,一会儿连续卖好几个。而且中间还会出现,吕布 女、貂蝉 男的错误情况。
这种情况是因为生产是两步骤,第一步name
赋值,第二部 gender
赋值。但是在这两步赋值的过程中线程被抢走,则赋值一半。
就会出现名字和性别不符的情况。
所以:生产的时候就不要消费,消费的途中就不要生产,不能互相抢。
那么我们要做的就是把生产和消费的线程同步起来,并且用同一把锁,锁起来,锁对象用 per ,也就是要生产的物品,正合适。
实现代码
注:为了看起来清晰,实体类用 Person 当货品了。
1.Person.java:
public class Person {
public String name;
public String gender;
//用于判断是否有人(物品)
public boolean hasPerson = false;
}
2.ProductThread.java:
public class ProductThread extends Thread {
Person per;
int num = 0;
public ProductThread(Person per) {
this.per = per;
}
@Override
public void run() {
while (num < 100) {
synchronized (per) {
if (per.hasPerson) {
// 如果有人,需要让当前线程等待,等待消费线程去消费
// 消费完了通知我,我来生产
try {
// 等待
per.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (num % 2 == 0) {
per.name = "吕布";
per.gender = "男";
} else {
per.name = "貂蝉";
per.gender = "女";
}
num++;
// 随即唤醒用当前锁对象作为同步锁对象的其他线程中的一个
per.notify();
per.hasPerson = true;
}
}
}
}
3.SellThread.java:
public class SellThread extends Thread {
Person per;
int num = 0;
public SellThread(Person per) {
this.per = per;
}
@Override
public void run() {
while (num < 100) {
synchronized (per) {
if (!per.hasPerson) {
// 如果没有人,需要让当前线程等待,等待生产线程去生产
// 生产完了通知我,我来消费
try {
per.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(per.name + " " + per.gender);
num++;
per.hasPerson = false;
// 唤醒用当前锁对象作为同步锁对象的其他所有线程
per.notifyAll();
}
}
}
}
4.Test.java:
public class Test {
public static void main(String[] args) {
Person per = new Person();
ProductThread pt = new ProductThread(per);
SellThread st = new SellThread(per);
pt.start();
st.start();
}
}
wait()和sleep()的比较
wait()
可以让当前线程处于阻塞状态。
sleep()
也可以让当前线程处于阻塞状态。
而且,两个方法参数都可以传入毫秒值,都是指定阻塞时间。
那么区别在哪里?
sleep()
不会自动释放锁。
wait()
会自动释放锁。
tips:
两个不同的线程类,不同的线程代码,但是只要保证运行起来,用的同步锁是同一个锁对象,那么同样可以实现同步。