繁体   English   中英

使用锁和条件进行线程同步

[英]Thread synchronization with Locks and Conditions


我在理解Java中的锁和条件时遇到问题,我不明白为什么我的代码最终陷入死锁。
我的程序由一个主线程和一个子线程组成,子线程是主线程的成员。 两个线程都在无限循环中运行,子线程的循环应该在从主线程接收到startCond信号后立即执行一次迭代。 主线程应等待finishCond信号继续。

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

public class LockTest {

    public static void main(String[] args) {
        LockTest lt = new LockTest();
        Mainthread m1 = lt.new Mainthread();
        m1.start();
    }

    public class Mainthread extends Thread {
        private Subthread sub = new Subthread();

        public void run(){
            System.out.println("Main start");
            sub.start();

            while(!isInterrupted()) {
                try {
                    sub.getStartLock().lock();
                    sub.getStartCond().signal();
                    sub.getStartLock().unlock();

                    sub.getFinishLock().lock();
                    sub.getFinishCond().await();
                    sub.getFinishLock().unlock();
                    System.out.println("Main done");
                } catch(InterruptedException e) {
                    e.printStackTrace();
                }

            }   
        }
    }

    public class Subthread extends Thread {
        private Lock startLock = new ReentrantLock();
        private Lock finishLock = new ReentrantLock();
        private Condition startCond = startLock.newCondition();
        private Condition finishCond = finishLock.newCondition();


        public Lock getStartLock() {
            return startLock;
        }

        public Lock getFinishLock() {
            return finishLock;
        }

        public Condition getStartCond() {
            return startCond;
        }

        public Condition getFinishCond() {
            return finishCond;
        }

        public void run() {
            System.out.println("Sub start");
            while(!isInterrupted()) {
                try {
                    startLock.lock();
                    startCond.await();
                    startLock.unlock();

                    finishLock.lock();
                    finishCond.signal();
                    finishLock.unlock();

                    System.out.println("Sub done");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

我的预期输出将是:
主要完成
子完成
(重复执行次数与在循环中执行的次数相同)。

有没有一种方法可以更轻松地解决此问题?

主线程启动,它创建新的子线程并启动它,但是在线程上调用start并不意味着该线程会立即接收处理器并且其代码将被实际执行。

Main,调用sub.getStartCond()。signal(); 但是此时子线程仍未运行,因此错过了该信号。

Main,在finishCond上等待。

Sub开始执行其run方法,进入开始条件并永远等待它。

僵局。

Signal仅唤醒当前正在等待的线程,它不会“记住”先前的调用。

使用信号量代替http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html

它具有“计算许可证”的语义。

可能会有更可靠的方法来执行此操作。 我建议使用使用计数1而不是条件初始化的CountDownLatch 主线程和子线程都可以共享闩锁的相同实例(因为主线程拥有子线程,这应该很容易)。 当您需要将信号发送给子对象时,子对象将调用await() ,而主对象将调用countDown() 我建议您将闩锁设为privatefinal

class ChildThread extends Thread {
  private final CountDownLatch signal;

  public ChildThread(CountDownLatch signal) {
    this.signal = signal;
  }

  public void run() {
    // The loop is necessary in case we get interrupted.
    while (true) {
      try {
        signal.await();
        break;
      } catch(InterruptedException ignored) {
      }
    }
    // do the work...
  }
}

class MainThread extends Thread {
  private final ChildThread child;
  private final CountDownLatch signalToChild;
  public MainThread() {
    signalToChild = new CountDownLatch(1);
    child = new ChildThread(signalToChild);
  }

  public void run() {
    // I can start the child right away but I'd rather make sure it
    // starts if the main thread has started.
    child.start();
    // prework
    // let's signal the child
    signalToChild.countDown();
    // now the child is working, let's go on with the main thread work
  }
}

之所以可行,是因为主线程和子线程实际上共享状态,即闩锁。 主线程在实际启动子线程之前是否减小锁存器没有关系,因为子线程将检查此共享状态以了解其是否可以启动。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM