Tag: 并发

Java RMI和同步方法

我正在研究“分布式系统”一书(由Tanenbaum和Van Steen撰写),他们说的东西似乎与许多人在Java RMI和同步方法上的想法相冲突。 我认为在远程对象实现上使用synchronized方法 (因此在服务器上运行的实际实现)即使对该方法的调用来自不同的客户端机器(通过代理调用该方法),也会阻止该方法的并发执行……又名Stub)。 我已经看到很多人都有相同的看法,例如在这里看看: Java RMI和线程同步问题 在本书中,它表示使用RMI时不会阻止同步方法的并发执行。 这是本书的相关摘录(您只能阅读粗体句子,但如果您愿意,可以阅读上下文): 逻辑上,远程对象中的阻塞很简单。 假设客户端A调用远程对象的同步方法。 要使对远程对象的访问看起来与本地对象完全相同,有必要在实现对象接口的客户端存根中阻止A,并且A有直接访问权限。 同样,在将其请求发送到服务器之前,还需要在本地阻止另一台机器上的另一个客户端。 结果是我们需要在不同的机器上同步不同的客户端。 正如我们在Chap中讨论的那样。 6,分布式同步可能相当复杂。 另一种方法是仅允许在服务器上进行阻止。 原则上,这样可以正常工作,但是当客户端在服务器处理其调用时崩溃时会出现问题。 正如我们在Chap中讨论的那样。 8,我们可能需要相对复杂的协议来处理这种情况,这可能会显着影响远程方法调用的整体性能。 因此,Java RMI的设计者选择仅限制对代理的远程对象的阻塞(Wollrath等,1996)。 这意味着将阻止同一进程中的线程同时访问同一个远程对象,但不同进程中的线程不会。 显然,这些同步语义很棘手:在语法层面(即,在阅读源代码时),我们可能会看到一个漂亮,干净的设计。 只有在实际执行分布式应用程序时,才能观察到应该在设计时处理的意外行为。 […] 我认为文章“Java系统的分布式对象模型”( 可在此处获得 )在文本中引用了Wollrath et all, 1996括号内。 然而,我在该论文中找到的唯一相关段落就是这一段: 由于本地和远程对象的故障模式不同,分布式等待和通知要求所涉及的实体之间的协议更复杂(例如,客户端崩溃不会导致远程对象永久锁定),因此,不能轻易地适应Java中的本地线程模型。 因此,客户端可以在远程引用上使用notify和wait方法,但该客户端必须知道此类操作不涉及实际的远程对象,只涉及远程对象的本地代理(存根)。 我是以错误的方式解释文本还是事实上说使用RMI时同步方法“不是那么同步”?

Java 8 ConcurrentHashMap

我发现ConcurrentHashMap已经在Java 8中完全重写为更“无锁”。 我浏览了get()方法的代码,看到没有明确的锁机制: public V get(Object key) { Node[] tab; Node e, p; int n, eh; K ek; int h = spread(key.hashCode()); if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n – 1) & h)) != null) { if ((eh = e.hash) == h) { if ((ek […]

使用递归函数进行并行编程?

问题的背景:我正在尝试编写一个利用多核处理器和并行处理的拼图解算法。 但是,理想/最简单的解决方案是简单的递归function。 分解解决方案以利用并行处理和递归函数的最佳方法是什么? 下面的代码是一个简单的解谜算法的解决方案(它正常工作)。 这个例子中的谜题很简单 – 有14个插槽编号为1-14。 每个拼图都有一个唯一的ID,一个范围告诉你它可以在哪里开始和停止(例如6-8意味着它只适合6-8槽)和价格。 该算法试图找到最大化解决方案价格的解决方案。 只有1个可以占用一个插槽,空插槽是可以接受的。 解决方案会告诉您使用了哪些部件以及总成本。 (为了简单起见,还要假设插槽1必须填充)。 我尝试将并行性和递归结合起来的解决方案如下所示:为每个使用插槽1的部分创建一个Task,然后在Task中递归查看其余部分,将它们插入剩余空间,同时最大化成本。 这是最好的解决方案(可能不是,这就是为什么我在这里)。 怎么改进? 使用并行/递归解决方案时还有其他好的建议吗? 虽然简单的递归在这里运行良好,但我想象一下这个有200个插槽和5000个拼图的拼图。 以下是此示例的解决方案: ID=1 Price=10.0 Range=1-6 ID=12 Price=8.0 Range=9-14 ID=15 Price=3.0 Range=7-8 public class Puzzle { public PuzzleSet calculateResults(PuzzleSet input) throws Exception { System.out.println(System.currentTimeMillis()); PuzzleSet results = getPriceMultithread((PuzzleSet)SerializationUtils.clone(input)); System.out.println(System.currentTimeMillis()); return results; } private PuzzleSet getPriceMultithread(PuzzleSet input) throws Exception { PuzzleSet […]

Java HashSet是否为只读的线程安全?

如果我在通过Collections.unmodifiableSet()运行它后有一个HashSet实例,它是否是线程安全的? 我问这个,因为Set文档声明它不是,但我只是执行读操作。

java中的volatile变量和内存障碍

我有一个由链接节点组成的数据结构。 您可以将其视为简单的LinkedList。 列表的每个节点由一些值和指向另一个节点的下一个字段组成,如果它是最后一个节点则为null。 第一个节点作为根,它没有值,只指向下一个节点。 所有其他节点实际上是不可变的,一旦它们被创建,它们的值和它们的下一个字段在生命期间都不会改变,除非正在处理与特定情况有关的结构。 一个(仅一个)线程将新节点添加到列表的前面。 它是通过构造一个新对象,设置其字段并将下一个字段设置为根指向的对象,然后将根的下一个字段设置为此新节点来实现的。 其他节点浏览仅执行读取的结构。 它们具有对根节点的引用,然后它们通过其他节点,直到它们找到正在查找的内容或到达列表的末尾。 我的问题是:是否足以让下一个字段变得易变? 根据我对java内存模型的理解,如果主线程(添加新节点的线程)在添加新节点时将执行易失性写入,那么一切都将很好地同步,并且不会发生任何不一致。 也是正确的假设在x86架构上读取volatile变量不会导致任何性能下降? 由于其他线程经常浏览读取下一个字段的结构,因此可以自由地完成此操作而不需要任何内存屏障等。 我还有一个问题。 要浏览结构的线程也将保留一些额外的节点。 这些节点将完全是线程本地的,它们将仅由创建它们的线程使用,并且根本不会被共享。 对于这些附加节点,下一个字段不必是易失性的。 此外,设置易失性下一字段将发出存储器屏障,这将导致不期望的性能损失。 我想知道有没有办法避免这种情况。 理想情况下,如果下一个字段有时会作为一个易失性字段而有时作为一个普通字段工作,那将是完美的;)或者如果我有完全控制并且可以在我需要的时候自行发出内存屏障。 编辑: 我也想知道是否有可能以不同的方式在不同的volatile变量上同步所有这些写入? 例如一些其他完全不相关的静态变量? 由于volatile写入刷新所有挂起的写入,下一个字段是不是可能不是易失性的,而是在更新线程完成所有工作后会写入不同的volatile变量? 它对我来说看起来不太安全,因为在关系之前没有发生,之前的写入可能会被重新排序。 可以使用值字段分配重新下载下一个字段分配,从而导致迭代线程观察到不一致的对象状态。 但也许有可能提出这样一个安全的方案吗? 这个怎么样: 更新线程首先构造一个新对象,初始化其值字段,将其下一个字段设置为根节点指向的节点, 对某个静态变量执行易失性写入 ,将根节点的下一个字段设置为新创建的节点

Java中任务并行库的等价性

我想在Java中没有相当于任务并行库(.NET 4.0)。 真的吗? .NET的这一特性提供了哪些改进,而Java并发却没有。

为什么通过newCachedThreadPool evil创建了ExecutorService?

Paul Tyma 演讲有这样一句: Executors.newCacheThreadPool恶,死死死 为什么这是邪恶的? 我会冒险猜测:是因为线程的数量会以无限的方式增长。 因此,如果达到了JVM的最大线程数,那么被斜线扫描的服务器可能会死掉?

扩展FutureTask,如何处理取消

我已经从java.util.concurrent扩展了FutureTask ,以提供回调来跟踪提交给ExecutorService的任务的ExecutorService 。 public class StatusTask extends FutureTask { private final ITaskStatusHandler statusHandler; public StatusTask(Callable callable, ITaskStatusHandler statusHandler){ super(callable); if (statusHandler == null) throw new NullPointerException(“statusHandler cannot be null”); this.statusHandler = statusHandler; statusHandler.TaskCreated(this); } @Override public void run() { statusHandler.TaskRunning(this); super.run(); } @Override protected void done() { super.done(); statusHandler.TaskCompleted(this); } } 现在,我看到的是,如果任务已提交,但最终排队并cancel(true); 任务 – 仍然调用run()方法 […]

挥发性如何实际起作用?

在Java中将变量标记为volatile可确保每个线程都看到上次写入的值而不是某些过时值。 我想知道这是如何实现的。 JVM是否发出特殊指令来刷新CPU内存或其他内容?

Spring:Singleton / session范围和并发

Spring bean的singleton / session范围是否要求必须同步对其所有字段的访问? 通过“synchronized”关键字或使用包“java.util.concurrent”中的某些类来说。 例如,这段代码不是线程安全的吗? (从这里复制/补充): @Component @SessionScoped public class ShoppingCart { private List items = new ArrayList(); public List getAllItems() { return items; } public void addItem(Product item) { items.add(item); } }