为什么同步块给出了错误的答案?

RaM*_*abU 2 java multithreading synchronization java-8

我正在努力学习同步.根据我学到的东西卡在这里下面的代码应该给8000作为最终结果,但我得到一个随机的结果,如下面的
包线程;

import java.time.LocalDateTime;

public class A implements Runnable {
    String name;
    static Integer j=0;
    A(String name){
        this.name=name;
    }
    @Override
    public synchronized void  run() {
        for(int i=1;i<=1000;i++){
            synchronized(this){
            A.j++;
            }
        }
        System.out.println(j);
    }

package threads;

public class MainClass {
public static void main(String args[]){
    Thread t1=new Thread(new A("i am thread A "));
    Thread t2=new Thread(new A("i am thread B "));
    Thread t3=new Thread(new A("i am thread C "));
    Thread t4=new Thread(new A("i am thread D "));
    Thread t5=new Thread(new A("i am thread E "));
    Thread t6=new Thread(new A("i am thread F "));
    Thread t7=new Thread(new A("i am thread G "));
    Thread t8=new Thread(new A("i am thread H "));
    t1.setPriority(Thread.MAX_PRIORITY);
    t8.setPriority(Thread.MIN_PRIORITY);
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();
    t6.start();
    t7.start();
    t8.start();
    try {
        t1.join();
        t2.join();
        t3.join();
        t4.join();
        t5.join();
        t6.join();
        t7.join();
        t8.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


}
}
Run Code Online (Sandbox Code Playgroud)

仍然得到输出像1293 2214 1403 3214 4214 5214 6224 7037任何人都可以向我解释如何实现同步和这里出了什么问题?

Bri*_*etz 12

认为这synchronized意味着"临界区" 是一个常见的错误,并且在同步块运行时没有其他线程会运行.但是,同步块仅对锁定同一锁的其他同步块是独占的.

你得到的答案("使用普通锁")是正确的,但并没有真正告诉你原因.另一个常见的错误是想synchronized为保护代码,当你真正应该思考它保护数据.任何共享的可变数据都应该由一个且只有一个锁保护,您应该确切地知道该锁是什么.(更复杂的锁定方案,就越有可能你就会知道什么锁定后卫的数据.)所以,你应该总是在"数据X被锁大号把守"术语来思考,然后确保你获得锁,只要大号您访问(读取写入)该数据.


Rav*_*ala 5

这将解决问题.你必须synchronize使用一个共享锁的所有线程,因为你是递增静态字段.否则,每个对象将拥有它自己的锁并并行增加静态字段,从而导致竞争条件.这就是为什么你没有得到正确的值,在这种情况下是8000.

package bookmarks;

public class A implements Runnable {
    String name;
    static Integer j = 0;
    private static Object lock = new Object();

    A(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 1000; i++) {
            synchronized (lock) {
                A.j++;
            }
        }
        System.out.println(j);

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 作为旁注,没有理由在这里使用盒装的"整数"; 将变量声明为`static int j = 0;`也可以. (2认同)