目录
1 几个重要的方法
1.1 wait()方法
使线程停止运行,会释放对象锁。
a. 该方法的三个特点:
- wait()方法会使当前线程调用该方法后进行等待,并且将该线程置入锁对象的等待队列中,直到接到通知或中断为止
- wait()方法只能在同步方法或同步代码块中调用,如果调用wait()方法时没有适当的锁,会抛出异常
- wait()方法执行后,当前线程释放锁,其他线程可以竞争该锁
b. wait()之后的线程继续执行的方法:
- 调用该对象的notify()方法唤醒线程
- 线程等待时调用interrupt()进行中断
1.2 notify()方法
唤醒线程
该方法的特点:
- notify( )方法也必须在同步方法或同步代码块中调用,用来唤醒等待在该对象上的线程,如果有多个线程等待,则任意挑选一个线程唤醒。
- notify( )方法执行后,唤醒线程不会立即释放对象锁,要等待唤醒线程全部执行完毕后才释放对象锁
1.3 notifyAll()方法
唤醒所有在该对象上等待的线程
2 单线程生产与消费者模型
2.1 改进前的模型
class Goods{
private String goodsName;
private int count;
//生产商品方法
public synchronized void set(String goodsName){
this.goodsName = goodsName;
this.count++;
System.out.println(Thread.currentThread().getName()+"生产"+goodsName+toString());
}
//消费商品方法
public synchronized void get(){
this.goodsName = goodsName;
this.count--;
System.out.println(Thread.currentThread().getName()+"消费"+goodsName+toString());
}
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
class Consume implements Runnable{
private Goods goods;
public Consume(Goods goods) {
this.goods = goods;
}
public void run() {
goods.get();
}
}
class Produce implements Runnable{
private Goods goods;
public Produce(Goods goods) {
this.goods = goods;
}
public void run() {
goods.set("爱豆");
}
}
public class Test{
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
Thread consumeThread = new Thread(new Consume(goods));
Thread produceThread = new Thread(new Produce(goods));
produceThread.start();
Thread.sleep(2000);
consumeThread.start();
}
}
运行结果:
但如果将代码改成先调用消费者线程,如下代码,则会出现消费为负数的情形:
public class Test{
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
Thread consumeThread = new Thread(new Consume(goods));
Thread produceThread = new Thread(new Produce(goods));
consumeThread.start();
Thread.sleep(2000);
produceThread.start();
}
}
运行结果:
2.1 改进后的模型
基于上述先消费后生产的情形, 我们可以做如下的改进, 引入wait()和notify():
class Goods{
private String goodsName;
private int count;
//生产商品方法
public synchronized void set(String goodsName){
if(count>0){
System.out.println("商品还有库存,等会再忙...");
try {
//等待消费者消费
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.goodsName = goodsName;
this.count++;
System.out.println(Thread.currentThread().getName()+"生产"+goodsName+toString());
//唤醒等待消费的线程
notify();
}
//消费商品方法
public synchronized void get(){
if(count==0){
System.out.println("商品买完了,等一哈~,马上就到了~~");
try {
//等待生产商品
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.goodsName = goodsName;
this.count--;
System.out.println(Thread.currentThread().getName()+"消费"+goodsName+toString());
//唤醒生产者进行生产
notify();
}
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
class Consume implements Runnable{
private Goods goods;
public Consume(Goods goods) {
this.goods = goods;
}
public void run() {
goods.get();
}
}
class Produce implements Runnable{
private Goods goods;
public Produce(Goods goods) {
this.goods = goods;
}
public void run() {
goods.set("爱豆");
}
}
public class Test{
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
Thread consumeThread = new Thread(new Consume(goods),"消费者");
Thread produceThread = new Thread(new Produce(goods),"生产者");
consumeThread.start();
Thread.sleep(2000);
produceThread.start();
}
}
运行结果:
这时就不会出现负消费的情形了~
3 多线程生产与消费者模型
3.1 有限个生产者和消费者
class Goods{
private String goodsName;
private int count;
//生产商品方法
public synchronized void set(String goodsName){
while (count>0){
System.out.println("商品还有库存,等会再忙...");
try {
//等待消费者消费
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.goodsName = goodsName;
this.count++;
System.out.println(Thread.currentThread().getName()+"生产"+goodsName+toString());
//唤醒等待消费的线程
notifyAll();
}
//消费商品方法
public synchronized void get(){
//不断判断执行 注!!!次数不能用if,if判断一次就结束了,程序运行会出现负消费~
while (count==0){
System.out.println("商品买完了,等一哈~,马上就到了~~");
try {
//等待生产商品
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.goodsName = goodsName;
this.count--;
System.out.println(Thread.currentThread().getName()+"消费"+goodsName+toString());
//唤醒生产者进行生产
notifyAll();
}
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
class Consume implements Runnable{
private Goods goods;
public Consume(Goods goods) {
this.goods = goods;
}
public void run() {
goods.get();
}
}
class Produce implements Runnable{
private Goods goods;
public Produce(Goods goods) {
this.goods = goods;
}
public void run() {
goods.set("爱豆");
}
}
public class Test{
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
//存储多个生产、消费者线程
List<Thread> list = new ArrayList<>();
//10个消费者线程
for(int i = 0;i < 10; i++){
Thread thread = new Thread(new Consume(goods),"消费者"+i);
list.add(thread);
}
//5个生产者模型
for(int i = 0;i < 5; i++){
Thread thread = new Thread(new Produce(goods),"生产者"+i);
list.add(thread);
}
for (Thread thread:list){
thread.start();
}
}
}
运行结果:
3.2 多个生产者和消费者
class Goods{
private String goodsName;
private int count;
public int getCount() {
return count;
}
//生产商品方法
public synchronized void set(String goodsName){
/*while (count>0){
System.out.println("商品还有库存,等会再忙...");
try {
//等待消费者消费
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.goodsName = goodsName;
this.count++;
System.out.println(Thread.currentThread().getName()+"生产"+goodsName+toString());
//唤醒等待消费的线程
notifyAll();
}
//消费商品方法
public synchronized void get(){
//不断判断执行 注!!!次数不能用if,if判断一次就结束了,程序运行会出现负消费~
while (count==0){
System.out.println("商品买完了,等一哈~,马上就到了~~");
try {
//等待生产商品
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.goodsName = goodsName;
this.count--;
System.out.println(Thread.currentThread().getName()+"消费"+goodsName+toString());
//唤醒生产者进行生产
notifyAll();
}
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
class Consume implements Runnable{
private Goods goods;
public Consume(Goods goods) {
this.goods = goods;
}
public void run() {
while (true){
goods.get();
}
}
}
class Produce implements Runnable{
private Goods goods;
public Produce(Goods goods) {
this.goods = goods;
}
public void run() {
//限制生产量
while (this.goods.getCount()<10){
goods.set("爱豆");
}
}
}
public class Test{
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
//存储多个生产、消费者线程
List<Thread> list = new ArrayList<>();
//10个消费者线程
for(int i = 0;i < 10; i++){
Thread thread = new Thread(new Consume(goods),"消费者"+i);
list.add(thread);
}
//5个生产者模型
for(int i = 0;i < 5; i++){
Thread thread = new Thread(new Produce(goods),"生产者"+i);
list.add(thread);
}
for (Thread thread:list){
thread.start();
}
}
}
运行结果是生产者和消费者迭代进行...