java线程的结果不一致

时间:2012-01-10 22:34:48

标签: java multithreading

我有一个实现runnable的线程类和一个int计数器作为实例变量。两个同步方法添加和子。当我以某种方式运行我的测试类时,它会在几次打印错误的结果。据我所知,当一个方法同步时,整个对象将被锁定以供其他线程访问,每当我们得到相同的结果时,这个逻辑是什么?有些情况并非如此。我错过了什么吗?

我的机器是Windows 7,64位。

 public class ThreadClass implements Runnable {

        int counter = 0;

        @Override
        public void run() {
            add();
            sub();
        }

        public synchronized void add() {
            System.out.println("ADD counter" + (counter = counter + 1));
        }

        public synchronized void sub() {
            System.out.println("SUB counter" + (counter = counter - 1));
        }
    }

识别TestClass

public class ThreadTest {

    public static void main(String args[]) {
        ThreadClass tc = new ThreadClass();
        Thread tc0 = new Thread(tc);
        tc0.start();
        tc0.setPriority(Thread.MAX_PRIORITY);
        Thread tc1 = new Thread(tc);
        tc1.start();
        tc1.setPriority(Thread.NORM_PRIORITY);
        Thread tc2 = new Thread(tc);
        tc2.start();
        tc2.setPriority(Thread.MIN_PRIORITY);
    }
}

结果

ADD counter1
ADD counter2
SUB counter1
SUB counter0
ADD counter1
SUB counter0

注意:您可能需要进行几次运行才能产生这种不一致。

3 个答案:

答案 0 :(得分:5)

您的搜索结果是正确的。

在执行方法期间,获取对象的独占锁定,但在add()sub()调用之间,线程可以自由交错。

如果在所有线程运行后最终总共0,那么它们都没有覆盖eathother并且counter的访问权限已同步。

如果您希望counter仅从0转到1,并且从不点击2,请执行以下操作(这将呈现方法级同步只要没有涉及其他类,就是多余的):

@Override
public void run() {
    synchronize(this) {
        add();
        sub();
    }
}

但是,这使得线程的重点无用,因为您可以在单线程循环中执行此操作。

答案 1 :(得分:3)

同步确实意味着所有线程都会在进入同步块之前阻止等待获取锁。只有一个线程可以锁定对象,因此add()sub()方法中只能有一个线程。

但是,这并不意味着有关线程排序的任何其他内容。您正在启动三个线程 - 唯一的保证是它们不会一次运行addsub方法而相互踩踏。线程1可以调用add(),然后线程3可以调用add(),然后线程2可以调用add(),然后他们都可以调用sub()。或者他们都可以分别致电add()然后sub()。或者任何混合 - 唯一的要求是每个线程在调用add()之前调用sub()并且没有两个线程将调用add()sub()而另一个线程在其中方法

除此之外:在某些情况下,它可能会在this上同步,因为它是公开的 - 通常首选使用内部私有Object来锁定,以便其他呼叫者无法锁定并违反您设计的任何锁定策略。

答案 2 :(得分:2)

任何一组结果都没有错。它们与您的代码完全一致。不保证多线程的运行顺序。

您的“同步”方法可确保您获得有效结果 - 每次调用add实际上都会添加一个,每次调用sub实际上都会减去一个。没有它们,你可以得到零以外的最终结果。