2009年11月,我去了No Fluff Just Stuff。 演讲之一是Brian Goetz的,主题是Java并发。 由于某种原因,他的议程幻灯片上有一些项目未在他的演讲中涉及。

他介绍了一些策略,最后他指出了一个通用策略,他也说这是Java并发的一个很好的经验法则:将变量设为私有,并使所有访问它们的方法同步。

听起来很简单。 也许太好了,难以置信。 是否存在这种并发技术不足的情况/应用程序? 主要依靠这种技术是否可以在具有大量事务或大型数据集的系统中很好地工作? 这样做的潜在缺点是什么?

#1楼 票数:4

是否存在这种并发技术不足的情况/应用程序?

如果您要跨多个这些方法执行要同步的操作,那么将每个方法标记为已同步是不够的。

主要依靠这种技术是否可以在具有大量事务或大型数据集的系统中很好地工作?

我对此表示怀疑,因为操作的同步界限似乎很少这么细。

这样做的潜在缺点是什么?

同步不是免费的,获得锁涉及成本(尽管通常很小)。 不必要的同步意味着不必要的成本。

坦率地说,在阅读了Java Concurrency in Practice之后 ,我很惊讶Goetz会给出这一建议,因为该书的主要课程是并发是一个复杂的话题,因此使应用程序线程安全和具有并发访问性能的解决方案非常重要。根据应用程序的具体情况进行定制,没有简单快捷的答案。

#2楼 票数:2

尽管对于并发编程来说是新手,但我认为并发“将所有成员设为私有并同步方法”并不是万能药。

看看: http : //download.oracle.com/javase/tutorial/essential/concurrency/index.html

同样,当涉及共享数据(可以由多个线程访问和/或修改的数据)时,您可能被迫使用同步方法。 在其他情况下,您可能不必使用synced关键字。

#3楼 票数:1

除了对性能的影响外,在某些情况下,此保护级别还不够。 例如,setX(),setY()。 如果您的API分别具有它们,则如果一个线程设置了x1,y1,而另一个线程设置了x2,y2,则可以以x1,y2结尾。 为避免这种情况,您需要在调用设置器之前锁定对象,或重新设计API以支持setXY(x,y)。

#4楼 票数:1

在许多情况下,这绝对是不够的。 考虑一下您要切换Vector的两个元素的位置的情况(基本上遵循所描述的战术Goetz)。 您的代码将包括对removeElementinsertElementAt的一系列调用(两者均已同步)。 但是,如果Vector对象在两次调用之间被另一个线程修改,则结果可能完全是垃圾。

尽管Goetz认为这是一种常见策略是正确的,但通常情况下需要更高级别的同步。 这就是为什么引入ArrayList的原因-它基本上是一个Vector,没有方法级同步的开销(通常是不必要的)。

#5楼 票数:1

这似乎有些严重的矫over过正。 它也不足以满足增量/获取序列的需要,在该序列中,另一个线程可能会交错插入set()调用。

如果我遇到了一个代码库,其中每个对象都有同步的getter / setter方法,那么我会对编码器产生严重的怀疑-我很可能以为他们最近才读到有关同步的文章,但并不完全理解它。

#6楼 票数:1

[matt b]引用的Goetz书中给出了一个清晰的例子。

将资金从帐户A转移到B:

synchronized (a) {
    synchronized (b) {
        // do the transfer
    }
}

似乎很清楚,但是如果两个线程同时尝试将$ 1从A传输到B,将另一个$ 2从B传输到A,并且时间片发生在同步块之间,会发生什么呢?

一种解决方案是订购它们并首先锁定较小的帐号。 本书包含更多示例和解决方案。 因此,没有简单的答案,但是使私有访问和同步成员访问权限足以满足许多应用程序的需求。

#7楼 票数:0

“将变量设为私有,并使所有访问它们的方法同步。” -本身就是合理的建议,并且可以在某些非常基本的情况下使代码具有线程安全性。

但是, 在更复杂的情况下 (例如,您需要在单个事务中一次修改两个不同的对象), 绝对不能确保正确的并发操作 通常,当您尝试将两个或多个锁定/同步操作粘合在一起时,会出现“ 锁不构成 ”的问题。

如果您对并发和可变状态感兴趣,我强烈建议您观看Rich Hickey撰写的有关“价值,身份和状态”的演示 它讨论了Clojure并发系统的设计,但是这些原则很重要,并且适用于任何语言。

#8楼 票数:0

该技术生成线程安全的代码,因为它可以保护Java变量免受多个线程的读/写中断。 但是,这并不意味着您的代码是正确的。 有时,同步适用于用单个方法不能很好表示的执行序列。 想象一个例程,它接受一个矩形并将宽度和长度设置为5。想象另一个例程在另一个线程上接受一个矩形,并将宽度设置为3,长度设置为6。即使setWidth和setLength是同步的,线程一可以设置宽度,线程二可以设置宽度和长度,线程一可以设置长度。 现在,矩形的宽度为5,长度为6。这根据任一线程都不正确。 请注意,如果矩形是不可变的,则不会发生此特定问题。

这是大型系统中的示例。 想象一下一个分布式系统,您需要在两台计算机上同步两个文件。 您需要在每个文件上获得某种同步锁。 如果有许多不同的线程争用不同的文件,则需要一种机制来确定谁获得了锁。 有各种各样的方案可以解决这个问题,所以这不是一个未知的问题,但是您可以看到它不仅仅像单个对象中的两个私有变量一样简单。

现在,您的后续行动:不利之处是什么? 如果您拥有不可变的资源,则可能无需防止不同线程进行多次读取。 结果,同步代码的额外开销是不必要的。 您的程序虽然正确,但由于不必要的同步,比使用相同算法实现的另一个正确程序要慢。

#9楼 票数:0

我莫名其妙地怀疑他会推荐这种方法,因为它确实存在缺陷,并且可能导致更多问题,甚至超出解决方案的范围。 但是,如果他按照您的描述方式推荐了它,那他是错的。

正如其他人已经提到的那样,该方法不提供原子性(不会自动执行多个操作)。 这是一个主要问题。

我想到其他一些可能的问题:

  • 所有成员私有且所有方法都已同步? 包括二传手和吸气剂? 那只是坏,坏,坏。
  • 如果性能真的很关键,并且您的读取将阻止/实现写入和其他读取,那该怎么办? 这也很糟糕,更好的选择是使用诸如ReentrantReadWriteLock之类的东西。
  • 容易出现死锁,请参阅提供的示例业力风

但最危险的事情是,有人可能会把它当作瑞士军刀,而事实并非如此。 有用的记住:同步从一开始就是Java的一部分,那么为什么还要烦恼所有替代方案呢? 必须明确一件事:如今,不仅出于性能原因,我们还具有所有其他功能:

  • 锁类
  • 大量并发类
  • 从Java 1.5开始,适当的volatile和良好的JMM

我的推荐? 尝试尽可能多地了解Java的并发性,那里有很多资源,Google(或与此相关的任何体面的SE)是您最好的朋友。 只是准备好花些时间,这并不容易,而且如果您真的想了解兔子洞下的情况,它会变得很深。 当今和未来的CPU以及越来越多的线程执行单元[将]使并发技能“必不可少”,因此没有理由跳过这一点。

#10楼 票数:0

我很确定我知道您正在考虑哪个演示文稿,并且您跳过了很多步骤。

该演示文稿中给出的建议是:-封装您的状态。 (这里没有争议)。 -如果需要同步访问状态,请封装该同步,也就是说,这对在客户端上导出同步要求是一个不好的要求。

要从此处“使访问它们的所有变量同步”,就是跳过对共享哪些变量以及用于同步访问该状态的逻辑策略的分析,而直接跳至“同步所有内容”。

  ask by Eric translate from so

未解决问题?本站智能推荐:

3回复

Java并发-如何同步方法参数

我有一个与 Java 中的同步和并发相关的问题。 所以我有一个方法,像这样: 在我做这个改变之前,完整的方法loadData是同步的private synchronized boolean loadData 。 但是,我的要求是,如果说fundId - 1 正在处理,那么我可以允许并发处理除1 以外
4回复

JavaRMI和同步方法

我正在研究“分布式系统”一书(由Tanenbaum和Van Steen撰写),他们说的东西似乎与许多人在Java RMI和同步方法上的想法相冲突。 我认为在远程对象实现上使用synchronized方法 (因此在服务器上运行的实际实现)即使对该方法的调用来自不同的客户端机器(通过代理调用该方
5回复

同步方法Java

我对线程之间的同步有疑问。 确实,我有一个只读取静态变量的方法。 一些线程访问此变量,但没有写入,只有读取。 我必须声明Synchonized方法吗?
4回复

简单的Java并发问题

线程1: 线程2: 当某些条件已满时,我想从线程2唤醒线程1。 但是,当thread1.notify()被调用时, if(!conditionFullfiled) ***HERE*** this.wait();是全文件,则不会有问题if(!conditionFullfiled) ***
2回复

JavaWeb服务并发问题

我有一个java方法调用Web服务并根据响应更改数据库。 我的任务是在多个用户同时使用此应用程序时消除并发错误。 我试图整天使用各种类型的数据库锁定,但没有任何工作。 我终于尝试在进程请求方法中使用synchronized,这一切都奏效了。 我的整个应用程序是单线程的。 为什么同步
3回复

JavaIOStreams中的同步方法

在Java java中, java.io.InputStream类中的Java 1.0就有了方法 和 为什么这两种方法同步而其他方法都不同步?
2回复

Java同步方法和块

我正在尝试更全面地了解Java中多线程的同步。 我理解使用synchronized关键字背后的高级思想,以及它如何在线程之间提供互斥。 唯一的问题是,即使你删除了使用这个主题比我认为需要更混乱的synchronized关键字,我在网上和教科书中阅读的大多数例子仍能正常工作。 任何人都可
3回复

Java同步方法的用法

我试图掌握Java中同步方法的概念,但是至少在我看来遇到了令人困惑的行为。 在代码中: ...增量由两个胎面并行执行: Thread[Thread-0,5,main]Thread[Thread-1,5,main]Thread[Thread-0,5,main]Thread[Thread-1,