Java 避免竞争条件而不使用同步/锁

发布于 2024-12-18 17:46:17 字数 268 浏览 2 评论 0原文

为了避免竞争情况,我们可以同步共享变量上的写入和访问方法,将这些变量锁定到其他线程。

我的问题是是否有其他(更好)的方法来避免竞争条件?锁使程序变慢。

我发现的是:

  • 如果只有一个共享变量,则使用原子类。
  • 使用不可变容器来存储多个共享变量,并使用 volatile 声明该容器对象。 (我从《Java并发实践》一书中找到了这个方法)

我不确定它们是否比同步方式执行得更快,还有其他更好的方法吗?

谢谢

In order to avoid race condition, we can synchronize the write and access methods on the shared variables, to lock these variables to other threads.

My question is if there are other (better) ways to avoid race condition? Lock make the program slow.

What I found are:

  • using Atomic classes, if there is only one shared variable.
  • using a immutable container for multi shared variables and declare this container object with volatile. (I found this method from book "Java Concurrency in Practice")

I'm not sure if they perform faster than syncnronized way, is there any other better methods?

thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

风筝在阴天搁浅。 2024-12-25 17:46:17

避免状态。
使您的应用程序尽可能无状态
每个线程(操作序列)应该在开始时获取一个上下文,并使用该上下文将其作为参数从一个方法传递到另一个方法。

当此技术无法解决您的所有问题时,请使用事件驱动机制+消息队列)。
当您的代码必须与其他组件共享某些内容时,它会将事件(消息)抛出到某种总线(主题、队列等)。

组件可以注册侦听器来侦听事件并做出适当的反应。
在这种情况下,不存在竞争条件(将事件插入队列除外)。如果您使用现成的队列而不是自己编码,那么它应该足够高效。

另外,看一下 Actors 模型。

Avoid state.
Make your application as stateless as it is possible.
Each thread (sequence of actions) should take a context in the beginning and use this context passing it from method to method as a parameter.

When this technique does not solve all your problems, use the Event-Driven mechanism (+Messaging Queue).
When your code has to share something with other components it throws event (message) to some kind of bus (topic, queue, whatever).

Components can register listeners to listen for events and react appropriately.
In this case there are no race conditions (except inserting events to the queue). If you are using ready-to-use queue and not coding it yourself it should be efficient enough.

Also, take a look at the Actors model.

没有心的人 2024-12-25 17:46:17

由于其非阻塞行为,原子确实比经典锁更高效,即等待访问内存位置的线程不会进行上下文切换,这节省了大量时间。

当需要同步时,最好的指导方针可能是看看如何尽可能地减小关键部分的大小。总体思路包括:

  1. 当只有一部分线程需要写入时,使用读写锁而不是完全锁。
  2. 寻找重组代码的方法以减少关键部分的大小。
  3. 更新单个变量时使用原子。
  4. 请注意,一些传统上需要锁的算法和数据结构有无锁版本(但是它们更复杂)。

Atomics are indeed more efficient than classic locks due to their non-blocking behavior i.e. a thread waiting to access the memory location will not be context switched, which saves a lot of time.

Probably the best guideline when synchronization is needed is to see how you can reduce the critical section size as much as possible. General ideas include:

  1. Use read-write locks instead of full locks when only a part of the threads need to write.
  2. Find ways to restructure code in order to reduce the size of critical sections.
  3. Use atomics when updating a single variable.
  4. Note that some algorithms and data structures that traditionally need locks have lock-free versions (they are more complicated however).
盛装女皇 2024-12-25 17:46:17

好吧,首先,原子类使用锁定(通过同步和易失性关键字),就像您自己手动操作一样。

其次,不变性非常适合多线程,您不再需要监视器锁等,但那是因为您只能读取不可变对象,而不能修改它们。

如果您想避免多线程 Java 程序中的竞争条件(即,如果多个线程可以读取和写入相同的数据),则无法摆脱同步/易失性。如果您想要更好的性能,您最好的选择是至少避免一些内置的线程安全类,这些类会执行更通用的锁定,并制作您自己的实现,该实现与您的上下文更加相关,因此可能允许您使用更细粒度的同步和同步锁定获取。

查看 Ehcache 人员完成的 BlockingCache 实现;

http:// /www.massapi.com/source/ehcache-2.4.3/src/net/sf/ehcache/constructs/blocking/BlockingCache.java.html

Well, first off Atomic classes uses locking (via synchronized and volatile keywords) just as you'd do if you did it yourself by hand.

Second, immutability works great for multi-threading, you no longer need monitor locks and such, but that's because you can only read your immutables, you cand modify them.

You can't get rid of synchronized/volatile if you want to avoid race conditions in a multithreaded Java program (i.e. if the multiple threads cand read AND WRITE the same data). Your best bet is, if you want better performance, to avoid at least some of the built in thread safe classes which do sort of a more generic locking, and make your own implementation which is more tied to your context and thus might allow you to use more granullar synchronization & lock aquisition.

Check out this implementation of BlockingCache done by the Ehcache guys;

http://www.massapi.com/source/ehcache-2.4.3/src/net/sf/ehcache/constructs/blocking/BlockingCache.java.html

青朷 2024-12-25 17:46:17

另一种选择是使共享对象不可变。查看这篇文章了解更多详细信息。

One of the alternatives is to make shared objects immutable. Check out this post for more details.

裸钻 2024-12-25 17:46:17

您每秒最多可以执行 5000 万次锁定/解锁。如果您希望更有效,我建议使用更多的粗粒锁定。即不要锁定所有小东西,而是为较大的对象加锁。一旦拥有比线程多得多的锁,就不太可能发生争用,并且拥有更多的锁可能只会增加开销。

You can perform up to 50 million lock/unlocks per second. If you want this to be more efficient I suggest using more course grain locking. i.e. don't lock every little thing, but have locks for larger objects. Once you have much more locks than threads, you are less likely to have contention and having more locks may just add overhead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文