线程通信方式:
- 文件共享
- 网络通信
- 共享变量
- jdk提供的协调api:wait/notify,park/unpark。多用于多线程协调完成某一任务。
wait()/notify和park()/unpark()的区别
wait()和notify()是基于锁,调用wait()和notify()方法必须获得对象锁。park()/unpark()则不是,但是park()无法释放锁。
wait()和notify()实现生产者消费者模式
public class StopTest {
static class BAOZI{
public int count=0;
}
public static void main(String[] args) throws InterruptedException {
BAOZI count = new BAOZI();
Producter producter = new Producter();
producter.setCount(count);
consume consume = new consume();
consume.setCount(count);
consume.start();
producter.start();
}
}
class Producter extends Thread {
private StopTest.BAOZI count;
public void setCount(StopTest.BAOZI count) {
this.count = count;
}
@Override
public void run() {
while (true) {
synchronized (count) {
while(count.count>0){
try {
count.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count.count++;
System.out.println("生产第" + count.count + "个包子");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.notifyAll();
}
}
}
}
class consume extends Thread {
public void setCount(StopTest.BAOZI count) {
this.count = count;
}
private StopTest.BAOZI count;
@Override
public void run() {
while (true) {
synchronized (count) {
while (count.count<=0) {
try {
count.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费了第" + count.count + "个包子");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.count--;
count.notifyAll();
}
}
}
}
注意:在以上代码中有几个小小主要注意的点,首先判断是否wait()中需要使用while而不是if,原因是可能存在伪唤醒的情况,伪唤醒是有更为底层的指令造成的唤醒而不是因为调用了notify唤醒。其次为什么我要用一个包装类来实现计数,原因是如果直接用Integer类型,因为Integer类型的缓存原因,当我们++的时候其实指向的是应力仪对象了,结果就是会造成报错。类似的如果是Boolean或者String这种带有初始值的也是,修改了之后就是另一个对象了。