Нет условий гонки: два блока с разными блокировками, но с одинаковыми общими данными - PullRequest
0 голосов
/ 09 октября 2018

У меня есть два потока thread_1 и thread_2 , вызывающие разные методы для одного и того же объекта unsafeObj .

  • thread_1 звонки unsafeObj.incrementVAR_v1() 10 раз
  • thread_2 звонки unsafeObj.incrementVAR_v2() 10 раз

Оба эти метода экземпляра имеют synchronized -блок с различными блокировками (LOCK_1 и LOCK_2) , обращающимися к одному и тому же полю экземпляра VAR .

public void icrementVAR_v1() {
  synchronized(LOCK_1) {
    ++VAR;
    print("Thread 1: "  + VAR)
  }
}

public void incrementVAR_v2() {
  synchronized(LOCK_2) {
    ++VAR;
    print("Thread 2: " + VAR);
  }
}

? Учитывая, что эти два synchronized -блока используют разные блокировки, я бы ожидал одновременного доступа к VAR, что приведет к потере обновлений (VAR меньше 20).Это, однако, не то, что я наблюдаю.Может кто-нибудь объяснить мне, почему это не так?

Пример вывода:

Thread 2: 2
Thread 1: 1
Thread 2: 3
Thread 1: 4
Thread 2: 5
Thread 1: 6
Thread 2: 7
Thread 1: 8
Thread 2: 9
Thread 1: 10
Thread 2: 11
Thread 1: 12
Thread 2: 13
Thread 1: 14
Thread 2: 15
Thread 1: 16
Thread 2: 17
Thread 1: 18
Thread 2: 19
Thread 1: 20

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

просто для удовольствия сделать в 10 (конечно, это не гарантировано)

public class Main {

    public static void main(String[] args) {
        Thread t1=new Thread(()->{
            for(int i=0;i<10;i++){
                icrementVAR_v1();

            }
        }
        );
        Thread t2=new Thread(()->{
            for(int i=0;i<10;i++){
                incrementVAR_v2();

            }
        }
        );
        t1.start();
        t2.start();
    }
    static Object LOCK_1=new Object();
    static Object LOCK_2=new Object();
    static int VAR=0;
    public static void icrementVAR_v1() {
        synchronized(LOCK_1) {
            ++VAR;
            Thread.yield();
            System.out.println("Thread 1: "  + VAR);
        }
    }

    public static void incrementVAR_v2() {
        synchronized(LOCK_2) {
            ++VAR;
            Thread.yield();
            System.out.println("Thread 2: " + VAR);
        }
    }
    public static void print(String s){
        System.out.println(s);
    }

}

пример вывода:

Thread 1: 2
Thread 2: 2
Thread 1: 4
Thread 2: 5
Thread 1: 6
Thread 2: 7
Thread 1: 8
Thread 2: 9
Thread 1: 10
Thread 1: 11
Thread 2: 12
Thread 1: 13
Thread 2: 14
Thread 1: 15
Thread 2: 16
Thread 1: 17
Thread 2: 18
Thread 1: 19
Thread 2: 19
Thread 2: 20
0 голосов
/ 09 октября 2018

Как я и ожидал, одновременный доступ (из-за наличия двух разных блокировок) к полю VAR приводит к состоянию гонки , но для его наблюдения требуется большое количество итераций (в моем случае 100'000 итераций в каждом потоке).Извлеченные уроки:

  • ☝ Условия гонки трудно воспроизвести
  • ? Используйте большое количество итераций при попытке их воспроизвести
...