您的位置:首页 > 编程语言 > Java开发

Java学习日志(12-1-多线程中锁的等待与唤醒)

2016-08-15 00:00 656 查看
多线程间通信

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();
}

3ff0
}
}
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){

}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: