我有一个实现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
注意:您可能需要进行几次运行才能产生这种不一致。
答案 0 :(得分:5)
您的搜索结果是正确的。
在执行方法期间,获取对象的独占锁定,但在add()
和sub()
调用之间,线程可以自由交错。
如果在所有线程运行后最终总共0
,那么它们都没有覆盖eathother并且counter
的访问权限已同步。
如果您希望counter
仅从0
转到1
,并且从不点击2
,请执行以下操作(这将呈现方法级同步只要没有涉及其他类,就是多余的):
@Override
public void run() {
synchronize(this) {
add();
sub();
}
}
但是,这使得线程的重点无用,因为您可以在单线程循环中执行此操作。
答案 1 :(得分:3)
同步确实意味着所有线程都会在进入同步块之前阻止等待获取锁。只有一个线程可以锁定对象,因此add()
或sub()
方法中只能有一个线程。
但是,这并不意味着有关线程排序的任何其他内容。您正在启动三个线程 - 唯一的保证是它们不会一次运行add
或sub
方法而相互踩踏。线程1可以调用add()
,然后线程3可以调用add()
,然后线程2可以调用add()
,然后他们都可以调用sub()
。或者他们都可以分别致电add()
然后sub()
。或者任何混合 - 唯一的要求是每个线程在调用add()
之前调用sub()
并且没有两个线程将调用add()
或sub()
而另一个线程在其中方法
除此之外:在某些情况下,它可能会在this
上同步,因为它是公开的 - 通常首选使用内部私有Object
来锁定,以便其他呼叫者无法锁定并违反您设计的任何锁定策略。
答案 2 :(得分:2)
任何一组结果都没有错。它们与您的代码完全一致。不保证多线程的运行顺序。
您的“同步”方法可确保您获得有效结果 - 每次调用add
实际上都会添加一个,每次调用sub
实际上都会减去一个。没有它们,你可以得到零以外的最终结果。