РеэнтерантныйReadWriteLock. чтение и запись получают приоритет

Я исследую ReentrantReadWriteLock

фрагмент из java-документа:

Поток не получит блокировку чтения до тех пор, пока самый старый в настоящее время ожидающий поток записи не получит и не освободит блокировку записи.

Таким образом, как я понял.

длительность чтения – 1 единица времени

длительность записи – 3 единицы времени

  1. время 0 - получена блокировка записи
  2. время 1 - чтение блокировки попробовать чтение
  3. время 2 - запись блокировки попробовать запись

Таким образом, я ожидаю следующую последовательность:

  1. сначала напиши
  2. вторая запись
  3. читать

код моего эксперимента:

public class RWLockCalculator {
    static long initTime = System.currentTimeMillis();
    private static int calculatedValue = 0;
    private static ReadWriteLock lock = new ReentrantReadWriteLock();
    public void calculate(int value) {
        lock.writeLock().lock();
        try {           
            System.out.println("write lock acquired at "+ (System.currentTimeMillis()-RWLockCalculator.initTime));
            this.calculatedValue = 1;
            Thread.sleep(300);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public int getCalculatedValue() {
        lock.readLock().lock();
        try {           
            System.out.println("read lock acquired at "+ (System.currentTimeMillis()-RWLockCalculator.initTime));
            Thread.sleep(100);
            return calculatedValue;
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return -1;
        } finally {
            lock.readLock().unlock();
        }
    }
}

class Test {
    public static void main(String[] args) throws InterruptedException {
        new WriteThread().start();
        Thread.sleep(100);
        new ReadThread().start();
        Thread.sleep(100);
        new WriteThread().start();

    }
}

class ReadThread extends Thread {
    @Override
    public void run() {
        System.out.println(new RWLockCalculator().getCalculatedValue() + ", " + (System.currentTimeMillis() - RWLockCalculator.initTime));
    }
}

class WriteThread extends Thread {
    @Override
    public void run() {
        new RWLockCalculator().calculate(99);
        System.out.println("I have written in  " + (System.currentTimeMillis() - RWLockCalculator.initTime));
    }
}

вне:

write lock acquired at 0
I have written in  300
read lock acquired at 300
1, 400
write lock acquired at 400
I have written in  700

Таким образом я получаю

  1. сначала напиши
  2. читать
  3. вторая запись

Почему я получаю этот результат?

Можно ли нарушить порядок FIFO?

Обновлять

Пожалуйста, сравните два родственных фрагмента из java-документа (о справедливом режиме):

первый

Поток, пытающийся получить блокировку справедливого чтения (без повторного входа), заблокируется, если удерживается блокировка записи или существует ожидающий поток записи. Поток не получит блокировку чтения до тех пор, пока самый старый в настоящее время ожидающий поток записи не получит и не освободит блокировку записи. Конечно, если ожидающий модуль записи отказывается от своего ожидания, оставляя один или несколько потоков чтения в качестве самых длинных ожидающих в очереди со свободной блокировкой записи, тогда этим читателям будет назначена блокировка чтения.

второй:

Поток, который пытается получить справедливую блокировку записи (без повторного входа), будет заблокирован, если и блокировка чтения, и блокировка записи не свободны (что подразумевает отсутствие ожидающих потоков). (Обратите внимание, что неблокирующие методы ReentrantReadWriteLock.ReadLock.tryLock() и ReentrantReadWriteLock.WriteLock.tryLock() не учитывают эту справедливую настройку и получат блокировку, если это возможно, независимо от ожидающих потоков.)

Я не совсем понимаю смысл того, что там написано. Но я вижу, что ReentrantReadWriteLock использует разные политики для получения блокировки чтения и блокировки записи. Я предполагаю, что если бы политика в java-документе была такой же, не было бы двух отступов.

ReadLock может совместно использовать блокировки. Это только одно отличие?


person gstackoverflow    schedule 16.04.2014    source источник
comment
Я бы сказал, что самый старый ожидающий в настоящее время поток записи — это тот, в который поток чтения запрашивает блокировку. Таким образом, в вашем примере нет ожидающего писателя, а следующий читатель.   -  person SpaceTrucker    schedule 16.04.2014
comment
@SpaceTrucker, это просто честно? ФИФО?   -  person gstackoverflow    schedule 16.04.2014


Ответы (1)


Прежде всего, ReentrantReadWriteLock должен быть создан в честном режиме, чтобы установить определенный порядок получения блокировки:

private static ReadWriteLock lock = new ReentrantReadWriteLock(true);

Затем javadoc описывает вас случае довольно ясно:

Когда потоки построены как честные, они соревнуются за вход, используя политику приблизительного порядка прибытия. Когда удерживаемая в данный момент блокировка снята, блокировка записи будет назначена либо самому долго ожидающему одиночному потоку записи, либо, если есть группа потоков чтения, ожидающих дольше, чем все ожидающие потоки записи, этой группе будет назначена блокировка чтения.

Поскольку ваш поток чтения ждал дольше, чем второй поток записи, он получает блокировку перед потоком записи.

person axtavt    schedule 16.04.2014
comment
Можно ли нарушить порядок FIFO? - person gstackoverflow; 16.04.2014
comment
все потоки стоят в общей очереди. независимо от того, хотите ли вы получить блокировку записи или чтения? - person gstackoverflow; 16.04.2014
comment
Политики блокировки чтения и записи должны быть разными, поскольку блокировка записи является монопольной, а блокировка чтения — нет. Насколько я понимаю, он по сути действует как очередь FIFO для потоков записи и групп потоков чтения (которые могут совместно использовать блокировку). - person axtavt; 16.04.2014