В этой Java-программе есть многопоточные конфликты.как это объяснить? - PullRequest
0 голосов
/ 11 апреля 2019

моя программа:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class test implements Runnable{
    private static int i;
    private static volatile Integer vi = 0;
    private static AtomicInteger ai = new AtomicInteger();
    private static Integer si = 0;
    private static int ri;
    private static AtomicInteger flag = new AtomicInteger();
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        for(int k=0;k<200000;k++){
            i++;
            vi++;
            ai.incrementAndGet();
            synchronized (si){
                si++;
            }
            lock.lock();
            try{
                ri++;
            }finally {
                lock.unlock();
            }
        }
        flag.incrementAndGet();
    }
    public static void main(String[] args) throws InterruptedException{
        test t1 = new test();
        test t2 = new test();
        ExecutorService exec1 = Executors.newCachedThreadPool();
        ExecutorService exec2 = Executors.newCachedThreadPool();
        exec1.execute(t1);
        exec1.execute(t2);
        while(true){
            if(flag.intValue()==2){
                System.out.println("i>>>>>>"+i);
                System.out.println("vi>>>>>>"+vi);
                System.out.println("ai>>>>>>"+ai);
                System.out.println("si>>>>>>"+si);
                System.out.println("ri>>>>>>"+ri);
                break;
            }
            Thread.sleep(50);
        }
    }
}

результат:

vi>>>>>>340217
ai>>>>>>400000
si>>>>>>364359
ri>>>>>>397043

Может кто-нибудь помочь объяснить, как работает эта многопоточная программа? результат показывает, что vi не равен 400000, что вполне разумно. но почему си и ри не равны 400000? Си синхронизируется, а ри синхронизируется блокировками.

Ответы [ 2 ]

3 голосов
/ 11 апреля 2019

Вы не синхронизируете доступ к переменным в главном потоке.

Вам необходима такая же синхронизация / блокировка для переменных, чтобы гарантировать видимость обновлений.

Однако , ваша синхронизация на si, вероятно, не будет работать так, как вы предполагали, потому что вы продолжаете присваивать этому полю новое значение: вместо этого синхронизируется на test.class.

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

0 голосов
/ 11 апреля 2019

lock не является статическим, поэтому каждый поток использует разные экземпляры, так как вы создаете два экземпляра test, следовательно, ri не синхронизируется. si не синхронизируется, поскольку целое число является неизменным, но si++ выполняет распаковку, приращение и упаковку. Вы должны синхронизироваться на другом конечном объекте, который является статическим для ex. или используйте один экземпляр test:

private final Object lockObj = new Object();
...
synchronized(lockObj){
  si++;
}
...