public class Test implements Runnable{
private String name;
public Test(String name){
this.name = name;
}
public void run() {
blah(name);
}
public synchronized void blah(String obj) {
System.out.println("Here: "+obj);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Test x = new Test("X");
Test y = new Test("Y");
Thread tx = new Thread(x);
Thread ty = new Thread(y);
tx.start();
ty.start();
}
这个例子可以帮助我理解同步,但我不知道。这是因为如果我删除单词synchronize
,它会打印相同的输出(随机)
答案 0 :(得分:2)
同步在这里无关紧要,因为你的两个线程都在自己的Runnable上进行同步。没有共享锁,也没有共享数据。
如果将相同的Runnable实例传递给每个线程,则它们将共享相同的锁。如果您的Runnable以线程不安全的方式执行某些操作(例如使用++来增加共享变量(Runnable的实例变量),或者将条目添加到共享ArrayList),那么您可以创建一种删除同步的情况代码中断(理解破坏可能不会可靠地发生,这就是使多线程编程变得有趣的原因)。
制作这样的玩具示例并不是对现实生活多线程的良好准备。线程不应该在实现锁定的业务中,它们应该访问强制执行自己的不变量的数据对象。
答案 1 :(得分:0)
您的示例在技术上是正确的,但同步块中没有与时序相关的冲突。因此,无论呼叫的顺序如何,您都不可能看到不同的输出。
此外,您创建了两个资源,并且两个资源之间没有跨线程通信,因此您有效地测试了两个同步块。
您需要一个在未同步时可能会中断的示例。
这是一个可以破解的例子
public class Counter {
int count;
public Counter() {
count = 0;
}
public int getCount() {
return count;
}
public /* need synchronized here */ void update(int value) {
int buffer = 0;
buffer = buffer + count;
buffer = buffer + value;
count = buffer;
}
}
public class UpdateCounter extends Thread {
public UpdateCounter(Counter counter, int amount) {
this.counter = counter;
this.name = name;
}
public void run() {
System.out.printf("Adding %d to count\n", amount);
counter.update(amount);
System.out.printf("Count is %d\n", counter.getCount());
}
}
public static void main(String[] args) {
Counter counter = new Counter();
UpdateCounter x = new UpdateCounter(counter, 30);
UpdateCounter y = new UpdateCounter(counter, 100);
x.start();
y.start();
}
通过这样的例子,人们最终会看到一系列线条,表明某些值被添加到计数器中,但计数器会更新错误的值。
这是因为一个线程最终将暂停一个缓冲区,其中包含" next"值,另一个线程将在同一个代码块中竞争,存储其" next"价值计入。然后暂停的线程将取消暂停,然后存储其下一个"值有效地删除了前面提到的线程所添加的数量。
通过添加synchronized关键字,只允许一个线程进入更新块,并且不会发生上述竞争条件。
请注意,这是一个可能因同步错误而失败的示例,而不是实现计数器的好方法。