Java基础笔记-第九记


Java 线程二

使用多线程时出现的以下问题

代码如下:

class Resource //资源类
{
	private String name;  
	private int count;
	public boolean flag;
	public synchronized void set(String name) {
		
		if(flag) {
			try {
				this.wait(); //等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name = name+"..."+count++;
		
		System.out.println(Thread.currentThread().getName()+ "生产者:" + this.name);
		flag = true;
		this.notify();//唤醒
	}
	public synchronized void out(){
		if(!flag) {
			try {
				this.wait(); //等待
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+".....消费者:" + this.name );
		flag = false;
		this.notify(); //唤醒
	}
}

class Producer implements Runnable{

	private Resource res;
	
	public Producer(Resource res) {
		this.res = res;
	}
	
	@Override
	public void run() {
		while(true){
			res.set("张三");			
		}
	}
}

class Consumer implements Runnable{

	private Resource res;
	
	public Consumer(Resource res) {
		this.res = res;
	}
	
	@Override
	public void run() {
		while(true){
			res.out();
		}
	}
}

public class Demo2 {

	public static void main(String[] args) {

		Resource res = new Resource();
		Producer pro = new Producer(res);
		Consumer con = new Consumer(res);
		
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}

}


现象:
关于生产者与消费者的多线程,如果线程大于2个,则会出现不规则的情况,可能出现生产者生产一个商品,但消费了两次,或者生产者生产两个商品,只消费了一个商品等情况。

原因:

当存在多个线程时,生产者生产完成后会唤醒另外一个线程,但在线程池里面等待的有生产方和消费方,这时有可能唤醒的是生产方的线程,而唤醒的这个线程又没有去判断标记,这样的话就有可能出现生产次数与消费次数不一样的情况。

解决方案:

由于将被唤醒的线程并没有判断标记,所以可以将原 if 结构 改成 while 结构,这样每次被唤醒时都会去判断标记,但有可能出现线程全等待的情况,这是因为每次唤醒时只唤醒一个线程,而这个线程会判断标记,如果标记不通过则会被等待,这样的话,所有线程都处在等待状态,没有谁来唤醒谁, 解决办法就是因为每个线程在唤醒时都会判断标记,并且有锁,那么干脆把所有线程唤醒 notifyAll , 这样就解决问题了。


代码如下:

class Resource //资源类
{
	private String name;  
	private int count;
	public boolean flag;
	public synchronized void set(String name) {
		
		while(flag) { //每次唤醒时都会进行判断标记
			try {
				this.wait(); //等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name = name+"..."+count++;
		
		System.out.println(Thread.currentThread().getName()+ "生产者:" + this.name);
		flag = true;
		this.notifyAll();//唤醒所有线程
	}
	public synchronized void out(){
		while(!flag) { //每次唤醒时都会进行判断标记
			try {
				this.wait(); //等待
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+".....消费者:" + this.name );
		flag = false;
		this.notifyAll(); //唤醒所有线程
	}
}

class Producer implements Runnable{

	private Resource res;
	
	public Producer(Resource res) {
		this.res = res;
	}
	
	@Override
	public void run() {
		while(true){
			res.set("张三");			
		}
	}
}

class Consumer implements Runnable{

	private Resource res;
	
	public Consumer(Resource res) {
		this.res = res;
	}
	
	@Override
	public void run() {
		while(true){
			res.out();
		}
	}
}

public class Demo2 {

	public static void main(String[] args) {

		Resource res = new Resource();
		Producer pro = new Producer(res);
		Consumer con = new Consumer(res);
		
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}

}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值