关于java中线程通信的锁定和条件

时间:2018-02-20 06:52:16

标签: java multithreading locking java-threads

我是一名java初学者,我在java中学习Thread时编写下面的代码。我想,如果我锁定Resource.set()并注释掉Lock.unlock()Resource.out()中的代码就无法执行,因为当我想执行方法时我无法解锁。顺便说一句,无论我在set()还是out()中注释解锁,程序都会以这种方式执行:

  

主题[线程1,5,主] .... ....生产
chicken1   螺纹[线程2,5,主] ....消耗.......... chicken1
  螺纹[线程0,5,主] .... ....生产
chicken2   线程[Thread-3,5,main] ....消耗.......... chicken2 ......

我想很长一段时间并且不了解它。我刚刚学会了,也许我的理解有误,所以我希望有人帮忙。   请原谅我可怜的英语。非常感谢你。我的代码在这里:

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

public class ThreadStudying {

public static void main(String[] args) {
    Resource r = new Resource();
    Thread t0 = new Thread(new Producer(r));
    Thread t1 = new Thread(new Producer(r));
    Thread t2 = new Thread(new Consumer(r));
    Thread t3 = new Thread(new Consumer(r));

    t0.start();
    t1.start();
    t2.start();
    t3.start();
}

static class Resource {
    private String name;
    private int count = 1;
    boolean isOut = false;

    Lock lock = new ReentrantLock();
    Condition pro_con = lock.newCondition();
    Condition consu_con = lock.newCondition();

    public void set(String name) {
        lock.lock();
        try {
            while (isOut) {
                try {
                    pro_con.await();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            this.name = name + count;
            System.out.println(Thread.currentThread() + "....Produce...." + this.name);
            count++;

            isOut = true;
            consu_con.signal();
        }
        finally {
            lock.unlock();
        }
    }

    public void out() {
        lock.lock();
        try {
            while (!isOut) {
                try {
                    consu_con.await();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(Thread.currentThread() + "....Consume.........." + this.name);

            isOut = false;
            pro_con.signal();
        }
        finally {
            //lock.unlock();
        }
    }
}

static class Producer implements Runnable {
    Resource r;

    Producer(Resource r) {
        this.r = r;
    }

    public void run() {
        while (true) {
            r.set("chicken");

            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

static class Consumer implements Runnable {
    Resource r;

    Consumer(Resource r) {
        this.r = r;
    }


    @Override
    public void run() {
        while (true) {
            r.out();
            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
  }
}

2 个答案:

答案 0 :(得分:1)

在制作人和消费者中,您通过

重复调用lock.await
while (true) {
    //
}

来自doc,当您致电lock.await时:

  

与此条件关联的锁定以原子方式释放

因此,无论您是否注释lock.unlock,生产者和消费者都不会被阻止。

P.S。使用以下代码记录有关获取和释放锁定的更多详细信息:

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

public class ThreadStudying {

public static void main(String[] args) {
    Resource r = new Resource();
    Thread t0 = new Thread(new Producer(r), "Producer 1");
    Thread t1 = new Thread(new Producer(r), "Producer 2");
    Thread t2 = new Thread(new Consumer(r), "Consumer 1");
    Thread t3 = new Thread(new Consumer(r), "Consumer 2");

    t0.start();
    t1.start();
    t2.start();
    t3.start();
}

static class Resource {
    private String name;
    private int count = 1;
    boolean isOut = false;

    Lock lock = new ReentrantLock();
    Condition pro_con = lock.newCondition();
    Condition consu_con = lock.newCondition();

    public void set(String name) {
        System.out.println(Thread.currentThread() + "before lock");
        lock.lock();
        System.out.println(Thread.currentThread() + "get lock");
        try {
            while (isOut) {
                try {
                    System.out.println(Thread.currentThread() + "release lock");
                    pro_con.await();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            this.name = name + count;
            System.out.println(Thread.currentThread() + "....Produce...." + this.name);
            count++;

            isOut = true;
            consu_con.signal();
        }
        finally {

        }
    }

    public void out() {
        System.out.println(Thread.currentThread() + "before lock");
        lock.lock();
        System.out.println(Thread.currentThread() + "get lock");
        try {
            while (!isOut) {
                try {
                    System.out.println(Thread.currentThread() + "release lock");
                    consu_con.await();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(Thread.currentThread() + "....Consume.........." + this.name);

            isOut = false;
            pro_con.signal();
        }
        finally {
            //lock.unlock();
        }
    }
}

static class Producer implements Runnable {
    Resource r;

    Producer(Resource r) {
        this.r = r;
    }

    public void run() {
        while (true) {
            r.set("chicken");

            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

static class Consumer implements Runnable {
    Resource r;

    Consumer(Resource r) {
        this.r = r;
    }


    @Override
    public void run() {
        while (true) {
            r.out();
            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
  }
}

答案 1 :(得分:0)

FirstOfAll,"如果我锁定Resource.set()并注释掉Lock.unlock(),则无法执行Resource.out()中的代码"。你的陈述是错误的。

让我澄清一下原因,

在您发布的代码中,out()无法解锁。我假设你没有问题,其中一个Consumer线程(t2t3)在获取锁时没有问题。

让我们说t2获取锁定,同时输入out()方法并且在退出out()方法时没有释放锁定。但是你忽略了out()方法在run() Runnable的Consumer方法中的无限循环中执行的事实。因此当t2退出out()时,睡眠时间为500毫秒;它仍然拥有锁。当它在下一次迭代中进入out()方法时,它会在已有的同一个锁上执行Lock.lock()。由于锁是Reentrant锁,它继续并执行await()释放锁定;等待锁定的其他线程(Producer个线程)有机会获得锁定。