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

时间:2018-03-14 14:28:30

标签: java multithreading java-8 synchronization

我正在尝试学习同步。根据我学到的东西卡在这里下面的代码应该给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();
    }


}
}

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

3 个答案:

答案 0 :(得分:12)

认为synchronized表示“临界区”是一个常见的错误,并且在同步块运行时没有其他线程会运行。但是,同步块仅对于锁定在同一个锁上的其他同步块是独占的。

你得到的答案(“使用普通锁”)是正确的,但并没有真正告诉你原因。另一个常见错误是将synchronized视为保护代码,而实际上您应该考虑保护数据。任何共享的可变数据都应该由一个且只有一个锁保护,您应该确切地知道该锁是什么。 (你的锁定方案越复杂,你就越不可能知道什么锁保护什么数据。)所以你应该总是考虑“数据X被锁L保护”,然后确保你每次获得锁L您访问(读取写入)该数据。

答案 1 :(得分: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);

    }

}

答案 2 :(得分:1)

代码中存在一些问题。

  • 问题1:synchronized(..)中添加的锁定对象不在其中共享 所有线程实例

  • 问题2:System.out.println(j);行应该在t8.join();之后结束,否则,您将获得8次输出。

经过纠正的代码

public class A implements Runnable {

    String name;
    static Integer j = 0;

    static Object lockObject = new Object();

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

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


    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();
        }
        System.out.println(A.j);

    }
}