Не работает Condition в ReentrantLock

Рейтинг: 0Ответов: 1Опубликовано: 16.12.2014

Основной класс:

public class TestMultithreading{

    static private final Lock lock = new ReentrantLock();
    static private final Condition cond1 = lock.newCondition();
    static private final Condition cond2 = lock.newCondition();
    static final ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);

    public static void main(String[] args) throws InterruptedException{

        ErrorHandler eh = new TestMultithreading().new ErrorHandler();

        Thread t1 = new Thread(new Customer(lock, cond1));
        Thread t2 = new Thread(new Customer(lock, cond1));
        Thread t3 = new Thread(new Thrower(lock, cond2));
        t1.start();
        t2.start();
        pool.schedule(t3, 1000, TimeUnit.MILLISECONDS); // Запускаю 3-ю катушку с откатом в 1с ибо как она срабатывает единажды, то чтоб сработала в время, когда уже на потоке Customer будет await()
    }
}

Дальше у нас есть 2 класса, которые реализовуют Runnable.

Первый Customer класс имеет 2 экземпляра, которые будут соревноваться за действия в методе run().
Тот, который шустрее, первым заблокирует метод с помощью ReentrantLock. Но в определенный момент в нем вызовется метод await через условие, что методу надо перескочить с count == 3.

public class Customer extends Methods implements Runnable{

    Lock lock;
    Condition cond;

    Customer(Lock lock, Condition cond){
        this.lock = lock;
        this.cond = cond;
    }

    @Override
    public void run() {

        lock.lock();
        try {
            while (count <= 10) {
                while (count == 3) {
                    cond.await();
                }
                System.out.println(count);
                increment();
                cond.signalAll();
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            lock.unlock();
        }   
    }    
}

Спустя 1 минуту запускается поток Thrower, который должен помочь перескочить c count == 3 на count == 4. И с помощью signallAll() оповестить зависший ранее процесс.

public class Thrower extends Methods implements Runnable{

    Lock lock;
    Condition cond;

    Thrower(Lock lock, Condition cond){
        this.lock = lock;
        this.cond = cond;
    }

    @Override
    public void run() {
        lock.lock();
        try {
            System.out.println("count" + count);
            errorCase();
            System.out.println("after count" + count);
            cond.signalAll();
            cond.await();
        } catch (InterruptedException ex) {
            Logger.getLogger(Thrower.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            lock.unlock();
        }
    }
}

Класс с методами и переменной, которые испозуют потоки:

class Methods{
    static int count = 0;
    void increment(){
        count++;
    }
    void errorCase(){
        count++;
    }   
}

В результате Customer засыпает, но не просыпается, даже после того как count == 4.

В чем же проблема?

0
1
2
count3
after count4
BUILD STOPPED (total time: 6 seconds)//программа остановленная вручную

Ответы

▲ 1Принят

Обратите внимание на эти строки:

Thread t1 = new Thread(new Customer(lock, cond1));
Thread t2 = new Thread(new Customer(lock, cond1));
Thread t3 = new Thread(new Thrower(lock, cond2));

Объект Thrower триггерит не то условие, которого ожидают объекты Customer. Если создать третий поток так:

Thread t3 = new Thread(new Thrower(lock, cond1));

то объекты Customer проснутся, и вывод программы будет таким:

0
1
2
count3
after count4
4
5
6
7
8
9
10
11