需要一个简单的同步示例

时间:2016-09-15 14:03:40

标签: java multithreading concurrency

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,它会打印相同的输出(随机)

2 个答案:

答案 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关键字,只允许一个线程进入更新块,并且不会发生上述竞争条件。

请注意,这是一个可能因同步错误而失败的示例,而不是实现计数器的好方法。