在this java tutorial中,有一些代码显示了解释synchronized
关键字使用的示例。我的观点是,为什么我不应该写这样的东西:
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
//private Object lock1 = new Object();
//private Object lock2 = new Object();
public void inc1() {
synchronized(c1) {
c1++;
}
}
public void inc2() {
synchronized(c2) {
c2++;
}
}
}
不打扰创建锁定对象?另外,为什么还要实例化锁定对象呢?我不能通过空引用吗?我想我在这里错过了一些东西。
另外,假设我在几个线程访问的同一个类中有两个公共同步方法。这两种方法永远不会同时执行,这是真的吗?如果答案是肯定的,是否有一种内置机制可以阻止一种方法饥饿(与其他方法相比,从未执行或执行过少次数)?
答案 0 :(得分:3)
首先你不能将原始变量传递给synchronized
,它需要一个引用。其次,教程只是一个显示防护块的示例。它不是c1,c2
它试图保护它,而是试图保护synchronized
块内的所有代码。
JVM使用操作系统的调度算法。
What is the JVM Scheduling algorithm?
因此,查看线程是否缺乏并不是JVM的责任。但是,您可以将线程的优先级指定为优先于其他线程来执行。
每个帖子都有优先权。具有较高优先级的线程优先于具有较低优先级的线程执行。每个线程可能也可能不会被标记为守护进程。当在某个线程中运行的代码创建一个新的Thread对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时才是守护进程线程。
自:https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
如果您担心这种情况,那么您必须自己实施。就像维护一个检查饥饿线程的线程一样,随着时间的推移,它增加了等待时间比其他线程更长的线程的优先级。
是的,已经同步的两个方法永远不会同时在同一个实例上执行。
答案 1 :(得分:3)
正如@ 11thdimension所回复,你不能在原始类型上同步(例如,长)。它必须是一个类对象。
所以,你可能想做类似以下的事情:
Long c1 = 0;
public void incC1() {
synchronized(c1) {
c1++;
}
}
这将无法正常工作,因为“c1 ++”是“c1 = c1 + 1”的快捷方式,它实际上将新对象分配给c1,因此,两个线程可能最终位于同一代码块中
要使锁正常工作,不应重新分配正在同步的对象。 (好吧,也许在极少数情况下,你真的知道自己在做什么。)
您无法将null对象传递给synchronized(...)语句。 Java正在有效地在ref'd对象上创建信号量,并使用该信息来防止多个线程访问相同的受保护资源。
您并不总是需要单独的锁定对象,就像同步方法一样。在这种情况下,类对象实例本身用于存储锁定信息,就像在方法iteslf中使用'this'一样:
public void incC1() {
synchronized(this) {
c1++;
}
}
答案 2 :(得分:1)
为什么还要实例化锁定对象?我不能只传递一个空引用吗?
正如其他人所提到的,你无法锁定long c1
,因为它是一个原始的。 Java锁定在与对象实例关联的监视器上。这就是为什么你也无法锁定null
。
thread tutorial正试图展示一个好的模式,即创建private final
锁定对象以精确控制您尝试保护的互斥锁位置。在synchronized
或其他this
对象上调用public
可能会导致外部呼叫者阻止您的方法,这可能不是您想要的。
本教程解释了这一点:
必须同步这些字段的所有更新,但没有理由阻止c1的更新与c2的更新交错 - 这样做会通过创建不必要的阻塞来减少并发性。我们不是使用同步方法或使用与此相关联的锁,而是仅创建两个对象来提供锁。
因此,他们还尝试允许c1
的更新和c2
的更新同时发生("交错")并且不会相互阻止,同时确保更新受到保护。
假设我在几个线程访问的同一个类中有两个公共同步方法。是不是两个方法永远不会同时执行?
如果一个线程在对象的synchronized
方法中工作,则如果另一个线程尝试同一个对象的相同或另一个synchronized
方法,则会阻止另一个线程。线程可以同时在不同的对象上运行方法。
如果答案是肯定的,是否有一种内置机制可以阻止一种方法饥饿(与其他方法相比,从未执行过或执行次数太少)?
如前所述,这是由操作系统的本机线程构造处理的。所有现代操作系统'处理线程饥饿,如果线程具有不同的优先级,这一点尤其重要。