跨线程传递数据时如何确保Java中的内存可见性 [英] How to Ensure Memory Visibility in Java when passing data across threads

查看:104
本文介绍了跨线程传递数据时如何确保Java中的内存可见性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类似于生产者消费者的模式,其中一些线程正在创建数据并定期传递放置该数据的块以供其他线程使用.

I have a producer consumer like pattern where some threads are creating data and periodically passing putting chunks of that data to be consumed by some other threads.

牢记Java内存模型,如何确保传递到使用者线程的数据具有完全的可见性"?

Keeping the Java Memory Model in mind, how do i ensure that the data passed to the consumer thread has full 'visibility'?

我知道java.util.concurrent中有专门用于此目的的数据结构,例如ConcurrentLinkedQueue,但是我想尽可能低级别地使用它而不用它们,并且对幕后的情况具有完全的透明性确保内存可见性部分.

I know there are data structures in java.util.concurrent like ConcurrentLinkedQueue that are built specifically for this, but I want to do this as low level as possible without utilizing those and have full transparency on what is going on under the covers to ensure the memory visibility part.

推荐答案

要传输数据,您需要一个可用于所有线程的字段.在您的情况下,确实需要某种集合来处理多个条目.如果您将字段final设置为引用(例如)ConcurrentLinkedQueue,则几乎可以完成.可以将该字段公开,每个人都可以看到,或者可以通过getter将其提供.

To transfer data, you need a field somewhere available to all threads. In your case it really needs to be some sort of collection to handle multiple entries. If you made the field final, referencing, say, a ConcurrentLinkedQueue, you'd pretty much be done. The field could be made public and everyone could see it, or you could make it available with a getter.

如果使用非同步队列,则您还有更多工作要做,因为您必须手动同步对其的所有访问,这意味着您必须跟踪所有使用情况.有吸气方法不容易.您不仅需要保护队列免于同时访问,还必须确保相互依赖的调用最终出现在同一同步块中.例如:

If you use an unsynchronized queue, you have more work to do, because you have to manually synchronize all access to it, which means you have to track down all usages; not easy when there's a getter method. Not only do you need to protect the queue from simultaneous access, you must make sure interdependent calls end up in the same synchronized block. For instance:

    if (!queue.isEmpty())  obj = queue.remove();

如果整个对象未同步,则queue完全能够告诉您它不为空,然后在尝试获取下一个元素时抛出NoSuchElementException. (ConcurrentLinkedQueue的界面经过专门设计,使您可以通过一个方法调用来执行类似的操作.即使您不想使用它,也请仔细看一下.)

If the whole thing is not synchronized, queue is perfectly capable of telling you it is not empty, then throwing a NoSuchElementException when you try to get the next element. (ConcurrentLinkedQueue's interface is specifically designed to let you do operations like this with one method call. Take a good look at it even if you don't want to use it.)

简单的解决方案是将队列包装在另一个对象中,该对象的方法经过精心选择均已同步.现在,包装好的类(即使是LinkedList或ArrayList)也将像CLQ一样起作用(如果您做对的话),并且可以将其自由释放到程序的其余部分.

The simple solution is to wrap the queue in another object whose methods are carefully chosen and all synchronized. The wrapped class, even if it's LinkedList or ArrayList, will now act (if you do it right) like CLQ, and it can be freely released to the rest of the program.

因此您将拥有什么是真正的全局字段,它具有对包装类的不可变(final)引用,该包装类包含一个LinkedList(例如),并具有使用LinkedList的同步方法存储和访问数据.像CLQ这样的包装器类将是线程安全的.

So you would have what is really a global field with an immutable (final) reference to a wrapper class, which contains a LinkedList (for example) and has synchronized methods that use the LinkedList to store and access data. The wrapper class, like CLQ, would be thread-safe.

对此可能需要一些变体.将包装程序与程序中的其他一些高级类组合在一起可能会很有意义.创建并提供嵌套类的实例也可能很有意义:也许一个只添加到队列中,另一个只从队列中删除. (您不能使用CLQ做到这一点.)

Some variants on this might be desirable. It might make sense to combine the wrapper with some other high-level class in your program. It might also make sense to create and make available instances of nested classes: perhaps one that only adds to the queue and one that only removes from it. (You couldn't do this with CLQ.)

最后一点:同步所有内容后,下一步就是弄清楚如何在不破坏线程安全的情况下进行不同步(以防止线程等待过多).在 this 上非常努力,最终您将重写ConcurrentLinkedQueue.

A final note: having synchronized everything, the next step is to figure out how to unsynchronize (to keep threads from waiting too much) without breaking thread safety. Work really hard on this, and you'll end up rewriting ConcurrentLinkedQueue.

这篇关于跨线程传递数据时如何确保Java中的内存可见性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆