一、需求
1、生产者每生产一样东西,消费者立马进行消费,生产与消费交替循环进行。
要交替则必须引入一个生产者消费者都能访问到的布尔型变量flag,定义在测试类中
当flag为false时,生产者生产,生产完毕falg置为true、循环变量加1,唤醒消费者,生产者等待。
当falg为true时,消费者消费,消费完毕flag置为falsea,循环变量加1,唤醒生产者,消费者等待。
2、生产者可以生产dove chocolate ,也可以生产哈尔滨啤酒,并且交替循环进行。
在同步块内引入for循环,循环变量为奇数生产dove巧克力,为偶数生产哈尔滨啤酒
3、要求生产的次数达到十次,且消费次数达到十次的时候,程序立马停止。
循环变量初始值为0,当循环变量小于10,才等待。否则可能导致线程死锁。
二、实现代码
package 多线程;
import java.util.TimerTask;
public class Producer extends TimerTask{
Cus_Pro_Test c=new Cus_Pro_Test();
@Override
public void run() {
synchronized ("") {
for(int i=0;i<10;) {
try {
//每隔1秒生产一次
Thread.sleep(1000);
//flag为false且i为偶数,生产dove巧克力
if(!c.flag && i%2==0) {
System.out.println(Thread.currentThread().getName()+"生产了dove巧克力~");
}
//flag为false且i为奇数,生产哈尔滨啤酒
if(!c.flag && i%2!=0) {
System.out.println(Thread.currentThread().getName()+"生产了哈尔滨啤酒~");
}
/*
* 生产成功需要做的事:
* 变量加1 flag置为true 唤醒消费者 生产者等待
* i等于10的时候不要等待,否则可能导致死锁
*/
i++;
c.flag=true;
"".notifyAll();
if(i<10)
"".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
///
package 多线程;
import java.util.TimerTask;
public class Customer extends TimerTask {
Cus_Pro_Test c=new Cus_Pro_Test();
@Override
public void run() {
synchronized ("") {
for(int i=0;i<10;) {
try {
//每隔1秒消费一次
Thread.sleep(1000);
//flag为true且i为偶数,消费dove巧克力
if(c.flag && i%2==0) {
System.out.println(Thread.currentThread().getName()+"消费了dove巧克力~");
}
//flag为false且i为奇数,生产哈尔滨啤酒
if(c.flag && i%2!=0) {
System.out.println(Thread.currentThread().getName()+"消费了哈尔滨啤酒~");
}
/*
* 消费成功需要做的事:
* 变量加1 flag置为false 唤醒生产者 消费者等待
* i等于10的时候不要等待,否则可能导致死锁
*/
i++;
c.flag=false;
"".notifyAll();
if(i<10)
"".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
///
package 多线程;
public class Cus_Pro_Test {
static boolean flag=false; //static保证本类的任何对象都能拿到同一个flag
public static void main(String[] args) {
new Thread(new Producer(),"生产者").start();
new Thread(new Customer(),"消费者").start();
}
}
三、运行效果
生产者生产了dove巧克力~
消费者消费了dove巧克力~
生产者生产了哈尔滨啤酒~
消费者消费了哈尔滨啤酒~
生产者生产了dove巧克力~
消费者消费了dove巧克力~
生产者生产了哈尔滨啤酒~
消费者消费了哈尔滨啤酒~
生产者生产了dove巧克力~
消费者消费了dove巧克力~
生产者生产了哈尔滨啤酒~
消费者消费了哈尔滨啤酒~
生产者生产了dove巧克力~
消费者消费了dove巧克力~
生产者生产了哈尔滨啤酒~
消费者消费了哈尔滨啤酒~
生产者生产了dove巧克力~
消费者消费了dove巧克力~
生产者生产了哈尔滨啤酒~
消费者消费了哈尔滨啤酒~
四、细节补充
添加同步锁的时候锁的是哪个对象,就要用哪个对象调用线程通信的方法。
但这并不妨碍我们锁一个空字符串,锁一个Integer类型的变量,我们只需要空字符串或Integer变量调用线程同步的方法即可。
记住:为了保证空字符串/Integer变量是同一个,他们一定不要直接new,声明的话可要可不要。
(这儿利用到了字符串和包装类(Float/Double除外)常量池的概念)