java多线程线程通信


一,java多线程使用Object对象的wait,notify或者notifyAll方法进行通信

      java的Object对象提供wait,notify和notifyAll方法。根据api中Object对象描述-------这三个方法调用时,应该只由对象监视器的所有者调用。即只能由synchronized所获得的锁对象进行调用,且只能在synchronized同步方法或者同步代码块中调用。

  • 使用synchronized同步代码块时,同步锁对象为括号内的同步锁对象,必须使用该对象来调用这三个方法
  • 使用synchronized修饰的同步方法时,同步锁对象为该类的默认实例,即this所指代的对象。对于静态类,锁对象为该类的字节码文件
使用生产消费者模型来解释这三个方法的使用:
错误的代码
<span style="font-size:14px;">package thread;
/*
 * 假设系统中有多条线程,这些线程分别代表取钱者和存钱者。现在系统有一种特殊的要求,
 * 系统要求存款者和取钱者不断的实现存款和取钱动作,而且要求每当存款者将钱存入指定账户后,
 * 取钱者立即将钱取走.不允许存款者两次存钱,也不允许取钱者两次取钱.
 *  我们通过设置一个旗标来标识账户中是否已有存款,有就为true,没有就标为false。
 */
public class Draw {

	public static void main(String[] args) {
		Acount acount = new Acount();
		new Thread(new Custom(acount, 800), "fupeng").start();
		new Thread(new Producer(acount, 800), "xiaoming1").start();
		new Thread(new Producer(acount, 800), "xiaoming2").start();
		new Thread(new Producer(acount, 800), "xiaoming3").start();
		new Thread(new Producer(acount, 800), "xiaoming4").start();
		new Thread(new Producer(acount, 800), "xiaoming5").start();
	}

}

class Custom implements Runnable{
	private Acount acount;
	private int drawMoney;
	public Custom(Acount acount,int drawMoney){
		this.acount = acount;
		this.drawMoney = drawMoney;
	}
	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(1000);
				this.acount.drawMoney(drawMoney);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class Producer implements Runnable{
	private Acount acount;
	private int saveMoney;
	public Producer(Acount acount, int saveMoney) {
		super();
		this.acount = acount;
		this.saveMoney = saveMoney;
	}
	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(1000);
				this.acount.saveMoney(saveMoney);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class Acount{
	private int money;
	private boolean flag = false;
	
	public synchronized void saveMoney(int saveMoney) {
		if(flag){
			try {
				System.out.println(Thread.currentThread().getName()+"wait并释放acount对象锁");
				this.wait();
				System.out.println("继续运行");
			}catch (InterruptedException e){ 
				e.printStackTrace();}
		}
		this.money+=saveMoney;
		System.out.println(Thread.currentThread().getName()+"存入:"+saveMoney);
		flag = true;
		this.notifyAll();
	}

	public synchronized void drawMoney(int drawMoney){
		if(!flag){
			try {
				System.out.println(Thread.currentThread().getName()+" wait并释放acount对象锁");
				wait();
				System.out.println("继续运行");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.money-=drawMoney;
		System.out.println(Thread.currentThread().getName()+"取出:"+drawMoney);
		System.out.println("余额:"+money);
		flag = false ; 
		notifyAll();
	}
}</span>

      在上述代码示例中,存在一个消费者线程,5个生产者线程。按照要求应该是:当有一个生产者线程存入钱之后,其他生产者线程不能再存入,只能等消费者取出之后再行存入。但是按照上述代码,运行中出现多个线程同时连续存入:

<strong>fupeng wait并释放acount对象锁
xiaoming5存入:800
继续运行
fupeng取出:800
余额:0
xiaoming1存入:800
xiaoming2wait并释放acount对象锁
xiaoming4wait并释放acount对象锁
xiaoming3wait并释放acount对象锁
xiaoming1wait并释放acount对象锁
xiaoming5wait并释放acount对象锁
fupeng取出:800
余额:0
继续运行
xiaoming5存入:800
继续运行
xiaoming1存入:800
继续运行
xiaoming3存入:800
继续运行
xiaoming4存入:800
继续运行
xiaoming2存入:800
fupeng取出:800
余额:3200</strong>

当消费者取出之后,5个生产者线程连续存入。

分析结果:当xiaoming1线程存入800之后,xiaoming2........xiaoming5执行存入操作,但flag标志为true,执行wait方法,释放同步锁,进入等待线程集。当fupeng线程取出之后,唤醒所有生产者线程,生产者线程接着获取最新状态同步锁对象,并接着从上次执行wait方法的地方接着继续执行,故出现1,2,3,4,5连续存入的现象。

注:在java多线程通信的方法中,当使用Object的wait,notify,notifyAll方法时:

若线程执行wait方法,该线程释放同步锁对象,并进入等待状态。当该线程被其他线程唤醒之后,重新获取最新状态的同步锁对象,并接着上次执行wait方法的地方继续执行。


   修改方法:

上述代码执行之后出现连续存入现象,全因为线程执行wait方法进入等待线程集之后,再被唤醒之后是继续接着上次wait方法的地方执行,故将wait后的代码放入else代码块中即可。

public class Draw {

	public static void main(String[] args) {
		Acount acount = new Acount();
		new Thread(new Custom(acount, 800), "fupeng").start();
		new Thread(new Producer(acount, 800), "xiaoming1").start();
		new Thread(new Producer(acount, 800), "xiaoming2").start();
		new Thread(new Producer(acount, 800), "xiaoming3").start();
		new Thread(new Producer(acount, 800), "xiaoming4").start();
		new Thread(new Producer(acount, 800), "xiaoming5").start();
	}

}

class Custom implements Runnable{
	private Acount acount;
	private int drawMoney;
	public Custom(Acount acount,int drawMoney){
		this.acount = acount;
		this.drawMoney = drawMoney;
	}
	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(1000);
				this.acount.drawMoney(drawMoney);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class Producer implements Runnable{
	private Acount acount;
	private int saveMoney;
	public Producer(Acount acount, int saveMoney) {
		super();
		this.acount = acount;
		this.saveMoney = saveMoney;
	}
	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(1000);
				this.acount.saveMoney(saveMoney);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class Acount{
	private int money;
	private boolean flag = false;
	
	public synchronized void saveMoney(int saveMoney) {
		if(flag){
			try {
				System.out.println(Thread.currentThread().getName()+"wait并释放acount对象锁");
				this.wait();
				System.out.println(Thread.currentThread().getName()+"继续运行");
			}catch (InterruptedException e){ 
				e.printStackTrace();}
		}else{
			this.money+=saveMoney;
			System.out.println(Thread.currentThread().getName()+"存入:"+saveMoney);
			flag = true;
			this.notifyAll();
		}
	}

	public synchronized void drawMoney(int drawMoney){
		if(!flag){
			try {
				System.out.println(Thread.currentThread().getName()+" wait并释放acount对象锁");
				wait();
				System.out.println(Thread.currentThread().getName()+"继续运行");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			this.money-=drawMoney;
			System.out.println(Thread.currentThread().getName()+"取出:"+drawMoney);
			System.out.println("余额:"+money);
			flag = false ; 
			notifyAll();
		}
	}
}

执行结果:

fupeng wait并释放acount对象锁
xiaoming2存入:800
fupeng继续运行
xiaoming1wait并释放acount对象锁
xiaoming3wait并释放acount对象锁
xiaoming4wait并释放acount对象锁
xiaoming5wait并释放acount对象锁
xiaoming2wait并释放acount对象锁
fupeng取出:800
余额:0
xiaoming2继续运行
xiaoming5继续运行
xiaoming4继续运行
xiaoming3继续运行
xiaoming1继续运行
xiaoming2存入:800
xiaoming1wait并释放acount对象锁
xiaoming3wait并释放acount对象锁
xiaoming4wait并释放acount对象锁
xiaoming5wait并释放acount对象锁
fupeng取出:800
余额:0

xiaoming2线程存入之后,生产者线程进入等待状态, 消费者取出钱之后notifyAll生产者线程,从上次wait方法的地方接着执行,执行完上次被打断的saveMoney方法。

接着xiaoming2线程又获取cpu执行资源,存入钱。。。。。。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章