Java:何时同步方法和块
我知道 synchronized
关键字用于防止多个线程同时访问同一代码块(整个方法或方法内的同步代码块),这有助于防止发生令人讨厌的事情,例如死锁。
我困惑的是什么时候适合使用这种机制:关于某个代码片段何时应该是线程安全的,存在什么经验法则?我能想到的唯一例子是当某件事发生的事件顺序至关重要时,但即便如此,我也无法想到一个实际的、具体的、现实世界的例子。
我从未编写过同步方法或块,因此“透过树木看到森林”对我来说有点困难。非常感谢任何上下文示例!提前致谢。
I understand that the synchronized
keyword is used to prevent multiple threads from accessing the same chunk of code (either a whole method or a block of synched code within a method) at the same time, and that this helps prevent nasty things from occurring, such as deadlocks.
What I'm stumped on is when it is appropriate to use this mechanism: what rule of thumb(s) exist as to when a certain fragment of code should be thread-safe? The only instance I can think of is when the order of events for something happening are critical, but even then I can't think of an actual, concrete, real-world example.
I've never written a synchronized method or block, and so "seeing the forest through the trees" is difficult for me, somehow. Any contextual examples are greatly appreciated! Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
当两个或多个线程需要修改同一资源,并且您希望强制在任何给定时间只有其中一个线程可以访问该资源时,请使用同步。例如,当您有一组应一起修改的变量时。
以下是 Java 教程中的示例:
整个部分非常有启发性:
Use
synchronized
when two or more threads need to modify the same resource, and you want to enforce that only one of them gets access to the resource at any given time. For example, when you have a set of variables that should be modified together.Here's an example from the Java tutorial:
The whole section is quite enlightening:
当多个线程作用于同一组数据时,并且您希望在第二个线程开始作用于数据之前,另一个线程可以看到一个线程正在执行的操作时,请使用同步。
需要使用同步关键字
当a) 如果您希望一次仅由一个线程(互斥体)操作数据
b) 如果您希望前一个线程所做的所有更改对另一个线程可见时,则 进来。
c) 当您希望线程完成的整个操作是原子的(即完全完成而不是中途离开)时。
您可以使用同步方法或块来解决上述所有情况。
现实世界中的主要用例就像客户生产者模式——比如一个线程获取数据,另一组线程验证和更新数据,另一个线程保存数据。
我发现它在内存数据库和实时操作中非常有用,因为毫秒是至关重要的。
Use synchronized when multiple threads acting on the same set of data and if you want what one thread is doing is visible by other thread before the second thread start acting on the data.
you want to use the synchronized keyword when
a) if you want the data to be operated on only by one thread at a time ( mutex)
b) if you want all the changes done by previous thread to be visible to the other thread when it comes in .
c) when you want the entire operation done by the thread to be atomic ( i.e completely finished instead of leaving in the middle) .
You can use synchronized methods or block to resolve all these above conditions.
The major use cases in the real world is like customer producer pattern -- like one thread fetching the data, another set of threads validating and updating the data and another thread persists the data.
I found it very useful in in memory databases and real time operations where milliseconds are critical.
何时使用同步:从不。历史表明,在一个重要的应用程序中几乎不可能做到这一点,因此提供并发性替代解决方案的库和语言越来越流行:参与者框架、软件事务内存等。
When to use synchronized: never. History has shown that it's near enough impossible to get it right in a non-trivial application, thus the rise in popularity of libraries and languages that provide alternate solutions to concurrency: actor frameworks, software transactional memory, and the like.
生产者-消费者是一个经典的上下文,如果需要正确的结果,则非常需要同步。生产者是一个生成一些单元的代码组件(Java 中的类),而消费者是另一个消耗这些生成单元的组件。生产者和消费者必须相互独立地工作,但必须产生有意义的行为。
一般来说,任何地方多个线程独立处理对象的某些状态,但只有在它们协调时才需要产生有意义的结果 - 您将需要使用同步语义。
Producer-consumer is a classic context where synchronization is highly needed if correct results are required. A producer is a code component ( a class in Java ) that produces some units and a Consumer is another component that consumes these units produced. The producers and consumers must work independent of each other , yet must produce meaningful behaviour.
In general , anywhere multiple threads process some state of an object independently , but need to produce results meaningful only when they are coordinated - you will need to use the
synchronized
semantics.虽然大多数讨论都集中在同步上,但我认为他们并没有真正讨论差异。那么让我们看看块同步和方法同步有何相同之处。
这两种方法完全相同。请注意,同步块上方或下方没有代码。如果它们是块之外的某些代码,则该代码将由多线程执行。它们之间的另一个区别是,您可以在不加锁的情况下运行的代码和在加锁的情况下运行的代码之间进行更改。如果只有一小部分需要在锁定下运行,则可以使用该方法来提高性能,并且如果该部分是热点,则该方法的核心可以运行多线程来提高性能。现在让我们看看块如何提供比方法更细粒度的同步。
在这种情况下,method1 和 method2 一次只允许其中一个线程同时存在,因为同步方法对此进行锁定。当然,如果我们在一个块中对此进行同步,那将是相同的。然而,我们不必总是对此进行同步。这里有一种方法可以使method1和method2锁定独立。
这是一个重要的区别,因为现在 method1 和 method2 可以同时执行,而使用同步方法则不允许这样做。您必须记住 method1 和 method2 在其代码中必须是独立的。如果 method1 修改实例变量,而 method2 读取该变量,则它们不是独立的,并且必须使用方法同步。但是,如果 method1 访问的实例变量与 method2 不同,则可以使用此技术。这一切意味着什么?这两种技术都不优于另一种。方法同步简单直接,但可能会因为锁定过多而导致性能较低。块同步解决了这个问题,但更复杂。
同步很重要。有些问题是没有它就无法解决的。但是,最好要小心,并在不必要时尽量不要使用它。有一些很棒的技术可以消除锁定并提高吞吐量,因此您还必须知道何时使用这些技术。这一切都需要经验和智慧。祝你好运。
While most of the discussion has focused on the synchronization I didn't think they really discussed the difference. So let's look at how block and method synchronization are the same.
These two methods are the exact same. Notice there is no code above or below the synchronized block. If they were the some code outside the block that code would be executed by multi-threads. Another distinction between them is that you can alter between code that runs without locking and code that runs under locking. This can be used to boost performance if only a small portion needs to run under locking, and the meat of the method can run multi-threaded boosting performance if that portion is a hotspot. Now let's see how blocks can offer more granularity of synchronization than methods.
In this case method1 AND method2 would only allow a thread at once in either of them at a time because synchronized methods lock on this. Of course if we synchronized on this in a block it would be the same. However, we don't have to synchronize on this always. Here is a way to make method1 and method2 locking independent.
This is important distinction because now method1 and method2 can be executed simultaneously where using synchronized methods will not allow this. You have to keep in mind that method1 and method2 MUST be independent in their code. If method1 modifies an instance variable, and method2 reads that variable they aren't independent, and you must use method synchronization. However, if method1 accesses separate instance variables than method2 then this technique can be used. What does that all mean? Neither technique is superior to the other. Method synchronization is simple and straight forward, but might have lower performance because it locks too much. Block synchronization fixes that problem, but its more complex.
Synchronization is important. There are problems that can't be done with out it. However, it's best to be careful, and try very hard to not use it when you don't have to. There are some great techniques that eliminate locking, and can improve throughput so you have to know when to use those as well. This all just takes experience and wisdom. Good luck.
如果满足以下条件,请使用同步方法:
(a) 您希望将方法的完整代码添加为线程安全的(简单来说,该代码一次最多由一个线程执行)
(b) 你不想对不同的方法使用不同的锁。向非静态方法添加同步需要实例对象锁。将同步添加到多个方法时,所有同步方法都将具有相同的锁,这意味着所有同步方法的任何代码一次最多由一个线程执行
如果满足以下条件,请使用同步块:
(a)您只想要其中的一部分代码方法是线程安全的。
(b) 您希望灵活地选择自己的锁(每个对象都包含监视器锁)。
代码的所有部分都处于一个同步锁(方法或块等)之下,只能由线程一次性执行。其余的就排队等待监视器锁定。
我的博客展示了一种使用同步块的美丽方法:
http://singletonjava.blogspot.com
Use synchronize methods if:
(a) you want to add the complete code of the method as thread-safe (in plain simple terms this code going to be executed by one thread max at a time)
(b) You dont want to use different lock for different method. Adding synchronization to non-static method takes the instance-object lock. While adding the synchronized to multiple methods, all will have same lock, which means any code of all synchronized method is going to be executed by one thread max at a time
Use synchronize block if:
(a) you only want a portion of code inside method to be thread-safe.
(b) You want flexibility to choose your own lock (every object contains monitor lock).
All portion of code comes under one synchronized lock (method or block whatever) can be executed by only thread at a go. Rest other will lined up waiting for the monitor lock.
A beautiful way to use synchronization block is shown at my blog here:
http://singletonjava.blogspot.com