【问题标题】:need a simple example for the synchronization需要一个简单的同步示例
【发布时间】:2023-03-25 13:32:01
【问题描述】:
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,它会打印相同的输出(随机)

【问题讨论】:

标签: java multithreading concurrency


【解决方案1】:

同步在这里无关紧要,因为您的两个线程都在各自的 Runnable 上同步。没有共享锁,也没有共享数据。

如果您将相同的 Runnable 实例传递给每个线程,那么它们将共享相同的锁。如果您的 Runnable 以线程不安全的方式执行某些操作(例如使用 ++ 来增加共享变量(Runnable 的实例变量),或者将条目添加到共享的 ArrayList),那么您可以创建一个删除同步的情况代码中断(理解中断可能不会可靠地发生,这就是使多线程编程变得有趣的原因)。

制作这样的玩具示例并不是为现实生活中的多线程做好准备。线程不应该参与实现锁定的业务,它们应该访问强制执行自己的不变量的数据对象。

【讨论】:

    【解决方案2】:

    您的示例在技术上是正确的,但您的同步块中没有时间相关冲突。因此,无论调用的顺序如何,您都不会看到不同的输出。

    此外,您创建了两个资源,并且两个资源之间没有跨线程通信,因此您有效地测试了两个同步块。

    您需要一个在不同步时会中断的示例。

    这是一个可以打破的例子

    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();
    
    }
    

    对于这样的示例,最终会看到一系列行,这些行表明正在向计数器添加一些值,但计数器会更新错误的值。

    这是因为一个线程最终会因保存“下一个”值的缓冲区而暂停,而另一个线程将在同一代码块中竞争,将其“下一个”值存储到计数中。然后暂停的线程将取消暂停,并存储它的“下一个”值,有效地删除由在它前面的线程添加的数量。

    通过添加同步关键字,只允许一个线程进入更新块,并且我上面描述的竞争条件不会发生。

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

    【讨论】:

      猜你喜欢
      • 2011-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-24
      • 2021-03-26
      • 1970-01-01
      相关资源
      最近更新 更多