为什么在使用并发时使字段成为私有的?

时间:2018-03-07 02:32:58

标签: java concurrency java.util.concurrent

我正在阅读在JAVA中思考(Ed4,由Bruce Eckel撰写),其中说:

  

请注意,在将字段设为私有时尤为重要   使用并发;否则synchronized关键字不能   防止另一个任务直接访问字段,从而   产生碰撞。

我很困惑,最后得到这个demo

public class SimpleSerial {

    public static void main(String[] args) throws IOException {
        ShareObject so = new ShareObject();
        Thread thread1 = new Thread(new ThreadOperation(so, "add"));
        Thread thread2 = new Thread(new ThreadOperation(so, "sub"));
        thread1.setDaemon(true);
        thread2.setDaemon(true);
        thread1.start();
        thread2.start();
        System.out.println("Press Enter to stop");
        System.in.read();
        System.out.println("Now, a=" + so.a + " b=" + so.b);
    }
}

class ThreadOperation implements Runnable {
    private String operation;
    private ShareObject so;

    public ThreadOperation(ShareObject so, String oper) {
        this.operation = oper;
        this.so = so;
    }

    public void run() {
        while (true) {
            if (operation.equals("add")) {
                so.add();
            } else {
                so.sub();
            }
        }
    }
}

class ShareObject {
    int a = 100;
    int b = 100;
    public synchronized void add() {
        ++a;
        ++b;
    }
    public synchronized void sub() {
        --a;
        --b;
    }
}

每次ab的值都不同时。那为什么呢?

该演示还提到了线程sleep()是否短时间,即重新编写ThreadOperation中的run()方法:

public void run() {
    while (true) {
        if (operation.equals("add")) {
            so.add();
        } else {
            so.sub();
        }
        try {
            TimeUnit.MILLISECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

然后ab的值相同。 再说一遍,为什么? sleep()背后会发生什么?

1 个答案:

答案 0 :(得分:0)

使用sleep(),当线程处于休眠状态时,println()很可能会执行。该程序仍然非线程安全。

您可以通过向synchronized添加print() SharedObject方法来解决此问题,例如:

public synchronized void print() {
    System.out.println("Now, a=" + a + " b=" + b);
}

并在main的最后一行调用它,而不是当前未同步的访问。