我试图理解java中的同步。我有以下示例
public class TestThr implements Runnable {
public static void main(String[] args) {
Thread t=new Thread(new TestThr());
Thread t1=new Thread(new TestThr());
t.start();
t1.start();
}
@Override
public void run() {
sync();
}
public synchronized void sync(){
for (int i=0;i<10;i++){
System.out.println("Running "+Thread.currentThread().getName());
}
}
}
输出 :
运行线程-0
运行线程1
运行线程-0
运行线程1
运行线程-0
运行线程1
运行线程1
运行线程1
运行线程-0
运行线程1
运行线程1
运行线程1
运行线程1
运行线程1
运行线程-0
运行线程-0
运行线程-0
运行线程-0
运行线程-0
运行线程-0
从上面的示例中,我期望一个线程(无论谁先输入)都将完成迭代,然后第二个线程将开始并完成,但是输出不一致。
请补充您的意见。
提前致谢。
最佳答案
您得到的输出是您不理解的,但它与您编写的代码一致。当您具有synchronized
方法时,您将锁定封闭类的实例。
public class TestThr implements Runnable {
...
public synchronized void sync() {
在您的示例中,
sync
方法为synchronized
,因此它将锁定在TestThr
的特定实例上。您正在像这样启动线程:Thread t = new Thread(new TestThr());
Thread t1 = new Thread(new TestThr());
这意味着每个线程都有自己的
TestThr
实例,因此它们锁定在不同的实例上并且不会彼此停止运行。如果您改为执行以下操作:
final TestThr testThr = new TestThr();
Thread t = new Thread(testThr);
Thread t1 = new Thread(testThr);
现在,这两个线程正在
TestThr
的同一实例上工作,因此它们将锁定在同一对象上,并且您的输出将达到您的期望。这仅适用,因为
TestThr
没有存储任何字段。如果您需要一个更复杂的类,那么我将一个锁对象传递给他们。就像是:final Object lockObject = new Object();
Thread t = new Thread(new TestThr(lockObject));
Thread t1 = new Thread(new TestThr(lockObject));
然后,在您的代码中执行以下操作:
public void sync() {
synchronized (lockObject) {
...
因此,该方法不会被锁定,但是您将在共享锁定对象上进行同步。
顺便说一句,考虑到循环的大小,一个线程很有可能会启动并运行循环,然后在另一个线程甚至启动之前退出。放置
System.out.println(...)
调用会减慢线程速度,因此可能会引起争用,但是如果删除输出,则需要担心。由于线程之间的竞争状况,可能很难测试像这样的线程程序。