Java学习日志(12-1-多线程中锁的等待与唤醒)
博客专区 > Almon 的博客 > 博客详情
Java学习日志(12-1-多线程中锁的等待与唤醒)
Almon 发表于1年前
Java学习日志(12-1-多线程中锁的等待与唤醒)
  • 发表于 1年前
  • 阅读 2
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 学生专属云服务套餐 10元起购>>>   

多线程间通信

Input------->变量库------->Output

    多个线程操作同一个资源,但是操作的动作不同

eg.同时输入输出会存在控制权转移导致输入一半就输出的问题

class Res{
	String name;
	String sex;
}
class Input implements Runnable{
	private Res r;
	Input(Res r){
		this.r=r;
	}
	public void run(){
		int x=0;
		while(true){
			if(x==0){
				r.name="Mike";
				r.sex="female";
			}
			else{
				r.name="Lily";
				r.sex="male";
			}
			x=(x+1)%2;
		}
	}
}
class Output implements Runnable{
	private Res r;
	Output(Res r){
		this.r=r;
	}
	public void run(){
		while(true){
			System.out.println(r.name+"___"+r.sex);
		}
	}
}
class InputOutputDemo{
	public static void main(String[] args){
		Res r=new Res();
		Input in=new Input(r);
		Output out=new Output(r);
		Thread t1=new Thread(in);
		Thread t2=new Thread(out);
		t1.start();
		t2.start();
	}
}

利用同步synchronized(唯一对象)解决控制权问题

class Res{
	String name;
	String sex;
}
class Input implements Runnable{
	private Res r;
	Input(Res r){
		this.r=r;
	}
	public void run(){
		int x=0;
		while(true){
			synchronized(r){    //共享数据
				if(x==0){
					r.name="Mike";
					r.sex="female";
				}
				else{
					r.name="Lily";
					r.sex="male";
				}
			}
			x=(x+1)%2;
		}
	}
}
class Output implements Runnable{
	private Res r;
	Output(Res r){
		this.r=r;
	}
	public void run(){
		while(true){
			synchronized(r){   //共享数据
				System.out.println(r.name+"___"+r.sex);
			}
		}
	}
}

将运行结果改为输入一条立即输出,依次循环——等待与唤醒

    wait()等待    notify()唤醒    notifyAll唤醒全部

    **因为是对持有锁的线程操作,因此只能用于同步之中,且必须标识锁——r.wait()

      定义在Object类中是因为只有同一个锁上的wait线程,可以被同一个锁notify

      锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中

class Res{
	String name;
	String sex;
	boolean flag=false;
}
class Input implements Runnable{
	private Res r;
	Input(Res r){
		this.r=r;
	}
	public void run(){
		int x=0;
		while(true){
			synchronized(r){
				if(r.flag){
					try{r.wait();}catch(Exception e){}
				}
				if(x==0){
					r.name="Mike";
					r.sex="female";
				}
				else{
					r.name="Lily";
					r.sex="male";
				}
				r.flag=true;
				r.notify();
			}
			x=(x+1)%2;
		}
	}
}
class Output implements Runnable{
	private Res r;
	Output(Res r){
		this.r=r;
	}
	public void run(){
		while(true){
			synchronized(r){
				if(!r.flag){
					try{r.wait();}catch(Exception e){}  //必须抛出异常,且必须标识锁
				}
				System.out.println(r.name+"___"+r.sex);
				r.flag=false;
				r.notify();
			}
		}
	}
}

对代码进行优化

class Res{
	private String name;			//权限私有化
	private String sex;
	private boolean flag=false;
	public synchronized void set(String name,String sex){	//提供对外接口,注意同步数据
		if(flag){
			try{this.wait();}catch(Exception e){}
			}
		this.name=name;
		this.sex=sex;
		flag=true;
		this.notify();
	}
	public synchronized void out(){
		if(!flag){
			try{this.wait();}catch(Exception e){}
		}
		System.out.println(name+"___"+sex);
		flag=false;
		this.notify();
	}
}
class Input implements Runnable{
	private Res r;
	Input(Res r){
		this.r=r;
	}
	public void run(){
		int x=0;
		while(true){
			if(x==0){
				r.set("Mike","Male");
			}
			else{
				r.set("Lily","Female");
			}
			x=(x+1)%2;
		}
	}
}
class Output implements Runnable{
	private Res r;
	Output(Res r){
		this.r=r;
	}
	public void run(){
		while(true){
			r.out();
		}
	}
}
class InputOutputDemo{
	public static void main(String[] args){
		Res r=new Res();
		new Thread(new Input(r)).start();
		new Thread(new Output(r)).start();
	}
}

练习:消费者与生产者通信

Ver 1.0

//存在问题:t1 t2唤醒后不再进行判断,可能生产出统一编号
class ProducerConsumerDemo{
	public static void main(String[] args){
		Resource r=new Resource();
		Producer p=new Producer(r);
		Consumer c=new Consumer(r);
		Thread t1=new Thread(p);
		Thread t2=new Thread(p);
		Thread t3=new Thread(c);
		Thread t4=new Thread(c);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
class Resource{
	private String name;
	private int count=1;
	private boolean flag=false;
	public synchronized void set(String name){
		if(flag){	//第一次判断flag为false,不执行wait(),第二次为true,执行wait().
			try{
				this.wait();
			}
			catch(Exception e){
				
			}
		}
		this.name=name+"--"+count++;
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
		flag=true;
		this.notify();
	}
	public synchronized void out(){
		if(!flag){	//第一次执行到这里的时候flag=true,不执行wait().
			try{
				this.wait();
			}
			catch(Exception e){
				
			}
		}
		System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
		flag=false;
		this.notify();
	}
}
class Producer implements Runnable{
	private Resource res;
	Producer(Resource res){
		this.res=res;
	}
	public void run(){
		while(true){
			res.set("+goods+");
		}
	}
}
class Consumer implements Runnable{
	private Resource res;
	Consumer(Resource res){
		this.res=res;
	}
	public void run(){
		while(true){
			res.out();
		}
	}
}

Ver 2.0

存在多个消费者与生产者时

将if语句改为while,单次判断变为多次判断。同时改为notifyAll避免全部wait

class Resource{
	private String name;
	private int count=1;
	private boolean flag=false;
	public synchronized void set(String name){
		while(flag){	
			try{
				this.wait();
			}
			catch(Exception e){
				
			}
		}
		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(Exception e){
				
			}
		}
		System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
		flag=false;
		this.notifyAll();
	}
}

总结

    对于多个生产者和消费者,使用while进行判断,让被唤醒的线程再次判断flag

    只用notify容易出现只唤醒本方线程的情况,导致所有线程都wait。

    notifyAll能够唤醒对方线程。

Java 5.0以后将同步synchronized替换为Lock操作

    将wait    notify等操作替换为Condition对象

    该对象可以对Lock锁进行操作

import java.util.concurrent.locks.*;

class Resource{
	private String name;
	private int count=1;
	private boolean flag=false;
	private Lock lock=new ReentrantLock();
	private Condition con_pro=lock.newCondition();
	private Condition con_con=lock.newCondition();
	public void set(String name)throws InterruptedException{
		lock.lock();
		try{
			while(flag){
				con_pro.await(); //只唤醒对方
			}
			this.name=name+"--"+count++;
			System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
			flag=true;
			con_con.signal();
		}
		finally{ //释放锁的动作一定要执行
			lock.unlock();
		}
	}
	public void out()throws InterruptedException{
		lock.lock();
		try{
			while(!flag){
				con_con.await();	
			}
			System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
			flag=false;
			con_pro.signal();
		}
		finally{
			lock.unlock();
		}
	}
}
class Producer implements Runnable{
	private Resource res;
	Producer(Resource res){
		this.res=res;
	}
	public void run(){
		while(true){
			try{
				res.set("+goods+");
			}
			catch(InterruptedException e){
				
			}
		}
	}
}
class Consumer implements Runnable{
	private Resource res;
	Consumer(Resource res){
		this.res=res;
	}
	public void run(){
		while(true){
			try{
				res.out();
			}
			catch(InterruptedException e){
				
			}
		}
	}
}

 

共有 人打赏支持
粉丝 2
博文 64
码字总数 44346
×
Almon
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: