【问题标题】:Synchronization in java - Can we set priority to a synchronized access in java?java中的同步——我们可以在java中为同步访问设置优先级吗?
【发布时间】:2013-11-10 11:21:03
【问题描述】:

同步通过在方法名称前放置一个 Synchronized 关键字来提供对对象或方法的独占访问。如果同时发生对一个方法的两个或多个访问,我想为一个特定的访问提供更高的优先级怎么办?我们可以这样做吗?

或者可能是我误解了 java 中同步的概念。请纠正我。 我还有其他问题,

在什么条件下我们应该使方法同步? 何时使方法同步?什么时候使块同步? 另外,如果我们使方法同步,类也会同步吗?这里有点困惑。

请帮忙。谢谢。

【问题讨论】:

标签: java multithreading synchronization


【解决方案1】:

在并发包中几乎可以满足您在多线程和同步中所需的所有解决方案,但是它需要您先考虑一下您要做什么。如果您只有一个非常基本的问题要解决,同步、等待和通知结构就像最基本的工具,但实际上大多数高级程序将(/应该)永远不会使用这些,而是​​依赖于 Concurrent 包中可用的工具。

您对线程的看法有些错误。没有更重要的线程,只有更重要的任务。这就是为什么 Java 清楚地区分线程、可运行对象和可调用对象的原因。

同步是一种防止多个线程进入特定代码部分的概念,这也是避免线程问题的最基本概念。如果多个线程访问某些数据,其中至少一个线程正在尝试修改该数据,则会出现这些问题。考虑一个由线程 A 读取的数组,同时由线程 B 写入。最终,线程 B 将写入线程 A 即将读取的单元格。现在由于线程的执行顺序是未定义的,线程 A 是否会读取旧值、新值或介于两者之间的东西也未定义。

围绕此访问的同步“锁定”是确保这种情况永远不会发生的一种非常粗暴的方式,并发包中提供了更复杂的工具,例如 CopyOnWriteArray,它通过为写入创建副本来无缝处理上述问题线程,所以线程 A 和线程 B 都不需要等待。其他工具可用于其他解决方案和问题。

如果您深入研究可用的工具,您很快就会发现它们非常复杂,使用它们的困难通常在于程序员而不是工具,因为无数小时的思考、改进和测试已经过去进入那些。

编辑:澄清一下为什么即使您在线程上设置了任务的重要性: 想象一条有 3 条车道的街道变窄为 1 条车道(同步块)和 5 辆汽车(线程)正在到达。让我们进一步假设有一个人(汽车调度员)必须定义哪些汽车获得第一行,哪些汽车获得其他行。由于只有一条车道,他最多只能将一辆车分配到第一排,其他车需要在后面。如果所有的汽车看起来都一样,他很可能会或多或少地随机分配订单,而已经在前面的汽车可能更可能留在前面,只是因为移动这些汽车会很麻烦。

现在假设一辆车的顶部有一个“美国总统在里面”的标志,所以调度员很可能会在他的决定中优先考虑这辆车。但即使标志在车上,他做出决定的原因也不是车(线程)的重要性,而是车内人(任务)的重要性。所以这个标志只是调度员的信息,这辆车运送更重要的人。然而无论这是否属实,调度员不能说(至少在没有检查的情况下不能说),所以他只需要相信车上的标志。

现在,如果在另一种情况下,所有 5 辆汽车都有“President inside”标志,调度员没有任何办法决定哪一辆先去,他再次处于与所有汽车都有相同的情况一点迹象都没有。

【讨论】:

  • 我有一项任务(比如)日历来维护日期/时间安排。现在我有一个线程(比如)UpdateDate 线程,每 24 小时更新一次日历日期。好的。并且有一些阅读器线程实际上会读取更新的日期值。现在我希望我的updateThread 在时间 12.00 具有更高的优先级来更改日期,这样读者线程不应该以读取旧日期结束。好的。所以这里只有一个任务Calender(没有其他任务与之竞争,那么你将如何确定任务的重要性?)。
  • 所以在我们需要更新日期的时候,我的 updateThread 在这里不是比其他所有时间都更重要吗?
  • 您可以将一个线程的优先级设置为高,然后将该重要任务分配给该线程(此处尽量准确)。然而,这并不能保证按时执行,它只是保证该线程将优先于其他具有较低优先级的线程。如果还有其他高优先级线程,则执行顺序未定义。有点难以理解,即使你在线程上设置了优先级,你这样做也是因为任务的优先级。高优先级线程也可以处理完全不重要的任务,这就是糟糕的设计。
  • “同步、等待和通知结构 [...] 大多数高级程序将(/应该)永远不会使用这些结构。”需要引用
  • @KarlRichter 这是常识:同步阻塞所有线程的执行,非阻塞同步(在所有 Java Concurrent 类中实现)不会阻塞执行。
【解决方案2】:

没有。可悲的是,Java 同步和等待/通知似乎是从非常糟糕的 Unix 示例中复制的,而不是几乎在其他任何地方都有优先级队列而不是雷鸣般的群。当Per Brinch Hansen, author of monitors and Objective Pascal, 看到 Java 时,他评论说“显然我的工作是徒劳的”。

【讨论】:

  • 哦..这是 java 的限制吗?因为很多时候我都需要在使用同步时优先考虑特定的访问。但在如此抽象的java世界里,我真的无法理解。
  • 它不存在。当您调用 notify() 时,会在 wait() 中阻塞的线程中进行任意选择以唤醒。如果你使用 notifyAll() 你会得到雷鸣般的羊群。如果你想要优先级,你必须自己综合它。参见例如RentrantLock 的 'fairness' 参数,它并没有给你优先级,只是最长的等待。
  • @TwoThe 问题是关于“同步”的。并发包也不提供基于优先级的同步,仅提供基于“公平”的同步。
  • @TwoThe 我真的不打算让你放弃关于 Java 的一个特性的非常具体的陈述,问题的主题,以及与最该领域的杰出从业者对 Java 的所有同步选项进行了概括性的声明。没有稻草人的争论谢谢。
【解决方案3】:

synchronized 的情况下,如果多个线程正在等待锁,则访问是随机的。但如果您需要先到先得:那么您可以使用`ReentrantLock(fairness)。 api是这样说的:

这个类的构造函数接受一个可选的公平参数。 当设置为 true 时,在争用情况下,锁倾向于授予对 等待时间最长的线程。

否则,如果您希望根据其他因素授予访问权限,那么我想构建一个应该不会很复杂。有一个类,当调用的lock 被阻塞时,如果其他线程正在执行。当调用unlock 时,它将根据您希望的任何算法解除线程阻塞。

【讨论】:

  • 请注意,尽管公平在现实生活中是一件好事,但它可能会降低高并发应用程序的整体吞吐量,因为它不允许当前到达锁的线程在以下情况下简单地运行其他线程已经在等待。
  • @isnot2bad 我了解,但您希望拥有 FIFO 服务,那么这是意料之中的。
  • 你是对的。我只想说,在很多情况下,吞吐量比公平更重要。我认为很难说在某些情况下确实需要公平。许多人只是机械地将此标志设置为真,因为他们认为公平是一件好事,但实际上他们只是没有真正考虑过。
  • @isnot2bad 完全同意 :)
  • @Jatin 这正是我想要的。这听起来可能有点矛盾,但是,分布式排序(!)确实是我正在寻找的,一个特定的要求。从你的 cmets 中得到启发,你有这种数据结构的原型吗?我可以在“分布式”部分工作,如果我能开始的话。
【解决方案4】:

在同步方法/块或对它们的访问之间没有“优先级”之类的东西。如果其他线程已经持有对象的监视器(即,如果另一个同步方法或synchronized (this) {} 块正在进行中并且没有通过调用this.wait() 放弃监视器),所有其他线程将不得不等待直到它完成.

java.util.concurrent 包中的某些类如果使用得当,可能会对您有所帮助,例如优先级队列。关于如何正确使用它们的完整指导可能超出了这个问题的范围——你应该先阅读a decent tutorial

【讨论】:

  • There's no such thing as "priority"? 但我认为,在多线程世界中,应该有一项规定,让一个特定线程高度优先访问该同步方法/块,类似于我们正常的操作系统进程管理。
  • @Winn 如果您的意思是在资源上等待的高优先级调用应该能够在该资源可用时立即访问该资源,即使低优先级调用正在等待,您只是描述了priority queue 的一种应用。如果您的意思是对方法的高优先级调用应该能够中断正在进行的低优先级调用,那么低优先级调用将需要定期检查高优先级调用是否正在等待,如果是,则屈服于直到更高优先级的调用完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-30
  • 1970-01-01
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多