关于Java多线程的Lock和Condition

antigenMHC 2019-10-15 10:05:56
public class Lock_and_Condition
{
public static void main(String[] args)
{
Resouce re = new Resouce();

Lock lock = new ReentrantLock();

ShengChanZhe i = new ShengChanZhe(re, (ReentrantLock)lock);
XiaoFeiZhe o = new XiaoFeiZhe(re ,(ReentrantLock)lock);

Thread t1 = new Thread(i, "生产者1");
Thread t2 = new Thread(i, "生产者2");
Thread t3 = new Thread(i, "生产者3");
Thread t4 = new Thread(o, "消费者1");
Thread t5 = new Thread(o, "消费者2");
Thread t6 = new Thread(o, "消费者3");

t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}

class Resouce
{
private String name;
private int count = 1;
private boolean flag;

public void setName(String name) {
this.name = name;
}

public void setCount(int count) {
this.count = count;
}

public void setFlag(boolean flag) {
this.flag = flag;
}

public String getName() {
return name;
}

public int getCount() {
return count;
}

public boolean getFlag()
{
return flag;
}
}

class XiaoFeiZhe implements Runnable
{
private Resouce res;
private Lock lock;
private Condition con;
XiaoFeiZhe(Resouce re, ReentrantLock lock)
{
this.res = re;
this.lock = lock;
con = this.lock.newCondition();
}
public void run()
{

while(true)
{
lock.lock(); //上锁,同步
//为了执行finally语句的内容,使用try
try
{
if(res.getFlag())
{
System.out.println(Thread.currentThread().getName()+"-----买走了第"+res.getCount()+"个"+res.getName());
res.setCount(res.getCount()+1);
res.setFlag(false);
con.signalAll(); //唤醒所有等待线程,赋予执行资格
}
else
{
try {
con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
finally {
lock.unlock();
//con.signalAll(); //唤醒所有等待线程,赋予执行资格
}
}
}
}

class ShengChanZhe implements Runnable
{
private Resouce re;
private Lock lock;
private Condition con;
ShengChanZhe(Resouce re, ReentrantLock lock)
{
this.re = re;
this.lock = lock;
con = this.lock.newCondition();
}
public void run()
{

while(true)
{
lock.lock();
try
{
if(re.getFlag())
{
try {
con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else
{
re.setName("混沌原核");
System.out.println(Thread.currentThread().getName()+"生产了第"+re.getCount()+"个"+re.getName());
re.setFlag(true);
con.signalAll(); //唤醒所有等待线程,赋予执行资格
}
}
finally {
lock.unlock();
}
}
}
}

上面这段代码在执行后会出现无法生产无法消费的挂起现象。。求大佬解答一下哪里错了
...全文
181 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
yuyishui 2019-10-22
  • 打赏
  • 举报
回复
引用 7 楼 antigenMHC 的回复:
引用 3 楼 yuyishui 的回复:
感觉是因为生产者了消费者new了不同的condition
我试着重新在主线程里面建立了一个Condition对象。。发现确实不会有抢占现象了。。但是生产者消费者本身不就是可以用不同的Condition对象来控制的吗,为什么会出现这种情况?
当然可以使用不同的Condition对象实例,但前提是要互相持有对方的实例引用。否则你如何做到生产者生产好了通知消费者进行消费呢? 生产者和消费者Condition对象分开的好处还在于可以进行精确的通知控制(如消费者仅唤醒生产者), 你现在的代码消费者线程中只能唤醒消费者,生产者同理
qq_39936465 2019-10-16
  • 打赏
  • 举报
回复
引用 楼主 antigenMHC 的回复:
上面这段代码在执行后会出现无法生产无法消费的挂起现象。。求大佬解答一下哪里错了


帮你修改了一下

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Lock_and_Condition
{
public static void main(String[] args)
{
Resouce re = new Resouce();

Lock lock = new ReentrantLock();

ShengChanZhe i = new ShengChanZhe(re, (ReentrantLock)lock);
XiaoFeiZhe o = new XiaoFeiZhe(re ,(ReentrantLock)lock);

Thread t1 = new Thread(i, "生产者1");
Thread t2 = new Thread(i, "生产者2");
Thread t3 = new Thread(i, "生产者3");
Thread t4 = new Thread(o, "消费者1");
Thread t5 = new Thread(o, "消费者2");
Thread t6 = new Thread(o, "消费者3");

t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}

class Resouce
{
private String name;
private int count = 1;
private boolean flag;

public void setName(String name) {
this.name = name;
}

public void setCount(int count) {
this.count = count;
}

public void setFlag(boolean flag) {
this.flag = flag;
}

public String getName() {
return name;
}

public int getCount() {
return count;
}

public boolean getFlag()
{
return flag;
}
}

class XiaoFeiZhe implements Runnable
{
private Resouce res;
private Lock lock;
private Condition con;
XiaoFeiZhe(Resouce re, ReentrantLock lock)
{
this.res = re;
this.lock = lock;
con = this.lock.newCondition();
}
public void run()
{

while(true)
{
lock.lock(); //上锁,同步
//为了执行finally语句的内容,使用try
try
{
if(res.getFlag())
{
System.out.println(Thread.currentThread().getName()+"-----买走了第"+res.getCount()+"个"+res.getName());
res.setCount(res.getCount()+1);
res.setFlag(false);
con.signalAll(); //唤醒所有等待线程,赋予执行资格
lock.unlock();
}
else
{
try {
lock.unlock();
con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}catch(Exception e) {

}
}
}
}

class ShengChanZhe implements Runnable
{
private Resouce re;
private Lock lock;
private Condition con;
ShengChanZhe(Resouce re, ReentrantLock lock)
{
this.re = re;
this.lock = lock;
con = this.lock.newCondition();
}
public void run()
{

while(true)
{
lock.lock();
try
{
if(re.getFlag())
{
try {
lock.unlock();
con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else
{
re.setName("混沌原核");
System.out.println(Thread.currentThread().getName()+"生产了第"+re.getCount()+"个"+re.getName());
re.setFlag(true);
con.signalAll();
//唤醒所有等待线程,赋予执行资格
lock.unlock();
}
}catch(Exception e){

}
}
}
}


yuyishui 2019-10-16
  • 打赏
  • 举报
回复
感觉是因为生产者了消费者new了不同的condition
qq_39936465 2019-10-16
  • 打赏
  • 举报
回复
或者按你的思路的话,先上锁后判断flag,如果false的情况你需要先释放锁再等待,而不是直接进入等待。
qq_39936465 2019-10-16
  • 打赏
  • 举报
回复
引用 楼主 antigenMHC 的回复:
上面这段代码在执行后会出现无法生产无法消费的挂起现象。。求大佬解答一下哪里错了


你先上锁在判断flag,这里明显有问题啊,因为经常都是抢占的,如果消费者抢了生产者的锁就会无限等待下去了。你这里明显应该先判断该生产者还是消费者,也就是先判断flag,然后再3个生产者来抢锁或3个消费者来抢锁。
antigenMHC 2019-10-16
  • 打赏
  • 举报
回复
引用 8 楼 qq_39936465 的回复:
[quote=引用 6 楼 antigenMHC 的回复:] 感谢大佬,那我这样理解可以吗:await是放弃了执行资格,unlock是让出了执行权(锁),如果await先执行的话就会出现没有执行资格,但却一直占用执行权(锁),从而导致其它线程无法执行的情况?
是的,因为等待需要别的线程来唤醒,但是其他线程都无法取得锁,所以无法通过其他线程来唤醒自身后再交出锁的控制权,所以要先交出控制权后再等待。[/quote]好的,谢谢大佬
qq_39936465 2019-10-16
  • 打赏
  • 举报
回复
引用 6 楼 antigenMHC 的回复:
感谢大佬,那我这样理解可以吗:await是放弃了执行资格,unlock是让出了执行权(锁),如果await先执行的话就会出现没有执行资格,但却一直占用执行权(锁),从而导致其它线程无法执行的情况?


是的,因为等待需要别的线程来唤醒,但是其他线程都无法取得锁,所以无法通过其他线程来唤醒自身后再交出锁的控制权,所以要先交出控制权后再等待。
antigenMHC 2019-10-16
  • 打赏
  • 举报
回复
引用 3 楼 yuyishui 的回复:
感觉是因为生产者了消费者new了不同的condition
我试着重新在主线程里面建立了一个Condition对象。。发现确实不会有抢占现象了。。但是生产者消费者本身不就是可以用不同的Condition对象来控制的吗,为什么会出现这种情况?
antigenMHC 2019-10-16
  • 打赏
  • 举报
回复
引用 4 楼 qq_39936465 的回复:
[quote=引用 楼主 antigenMHC 的回复:] 上面这段代码在执行后会出现无法生产无法消费的挂起现象。。求大佬解答一下哪里错了
帮你修改了一下

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Lock_and_Condition
{
    public static void main(String[] args)
    {
        Resouce re = new Resouce();

        Lock lock = new ReentrantLock();

        ShengChanZhe i = new ShengChanZhe(re, (ReentrantLock)lock);
        XiaoFeiZhe o = new XiaoFeiZhe(re ,(ReentrantLock)lock);

        Thread t1 = new Thread(i, "生产者1");
        Thread t2 = new Thread(i, "生产者2");
        Thread t3 = new Thread(i, "生产者3");
        Thread t4 = new Thread(o, "消费者1");
        Thread t5 = new Thread(o, "消费者2");
        Thread t6 = new Thread(o, "消费者3");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
    }
}

class Resouce
{
    private String name;
    private int count = 1;
    private boolean flag;

    public void setName(String name) {
        this.name = name;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public String getName() {
        return name;
    }

    public int getCount() {
        return count;
    }

    public boolean getFlag()
    {
        return flag;
    }
}

class XiaoFeiZhe implements Runnable
{
    private Resouce res;
    private Lock lock;
    private Condition con;
    XiaoFeiZhe(Resouce re, ReentrantLock lock)
    {
        this.res = re;
        this.lock = lock;
        con = this.lock.newCondition();
    }
    public void run()
    {

        while(true)
        {
            lock.lock();     //上锁,同步
            //为了执行finally语句的内容,使用try
            try
            {
                if(res.getFlag())
                {
                    System.out.println(Thread.currentThread().getName()+"-----买走了第"+res.getCount()+"个"+res.getName());
                    res.setCount(res.getCount()+1);
                    res.setFlag(false);
                    con.signalAll(); //唤醒所有等待线程,赋予执行资格
                    lock.unlock();
                }
                else
                {
                    try {
                    	lock.unlock();
                        con.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }catch(Exception e) {
            	
            }
        }
    }
}

class ShengChanZhe implements Runnable 
{
    private Resouce re;
    private Lock lock;
    private Condition con;
    ShengChanZhe(Resouce re, ReentrantLock lock)
    {
        this.re = re;
        this.lock = lock;
        con = this.lock.newCondition();
    }
    public void run()
    {

        while(true)
        {
            lock.lock();
            try
            {
                if(re.getFlag())
                {
                    try {
                    	lock.unlock();
                        con.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                else
                {
                    re.setName("混沌原核");
                    System.out.println(Thread.currentThread().getName()+"生产了第"+re.getCount()+"个"+re.getName());
                    re.setFlag(true);
                    con.signalAll();
                    //唤醒所有等待线程,赋予执行资格
                    lock.unlock();
                }
            }catch(Exception e){
            	
            }
        }
    }
}


[/quote]感谢大佬,那我这样理解可以吗:await是放弃了执行资格,unlock是让出了执行权(锁),如果await先执行的话就会出现没有执行资格,但却一直占用执行权(锁),从而导致其它线程无法执行的情况?
kkkkk0lllll 2019-10-16
  • 打赏
  • 举报
回复
消费者优先拿到锁后,不释放,导致生产者,始终不能拿到锁,永远不会唤醒消费者;从而进入相互等待

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧