Java线程 - 同步代码
为什么你必须指定哪个对象锁定了同步代码块?Java线程 - 同步代码
你不必指定哪个对象锁定了同步方法,因为它总是被'this'锁定(我相信)。
我有两个问题:
- 为什么你不能阻止比 “这个”其他对象的无静态方法?
- 为什么你必须指定阻止 同步代码的对象?
我已经阅读了SCJP for Java 6的第9章,但是我对此仍不清楚。
我意识到这可能是一个基本问题,但我是线程新手。
- 你可以用一个对象,但程序员通常 使用
this
或locker
的任何实例锁... - 因为它限制其他线程访问的代码部分 (代码处理单元),所以你确保整个该部分运行在 一致性和没有(即一个变量)会由另一个线程警报。
考虑:
a = 1;
a++;
线程一到达第二行,你希望a = 2
但另一个线程执行第一线,而不是2你有a = 1
的第一线和a = 2
的第二个线程。现在:
synchronized (whatever)
{
a = 1;
a++;
}
现在第二个线程将进入到code block
(体),直到第一个离开它(解除锁定)被阻止。
您可以指定任何对象,该对象应该在同步代码块上具有锁定。实际上,您根本不应该使用synchronize(this)
(或者可能要小心,请参阅Avoid synchronized(this) in Java?)。
为什么你不能阻止一个非静态方法的对象不是'this'?
您可以:
public void foo() {
synchronized (lock) {
...
}
}
为什么你必须指定已阻止同步代码的对象?
因为这就是语言设计者选择设计语言的方式。在实例方法上使用时,隐式使用this
作为锁。在块上使用时必须明确指定锁。
您可以。 代码
synchronized foo() {
// some stuff
}
在逻辑上等于代码
foo() {
synchronized(this) {
// some stuff
}
}
我说“逻辑”,因为这些实施例2产生不同的字节码。
如果方法foo()
是静态同步完成的类对象。
但是,您可能希望创建几个同步块,这些块在不同的对象上同步到一个类或甚至一个方法中。在这种情况下可以使用synchronized (lock)
其中lock
不是this
:
foo() {
synchronized(one) {}
///..........
synchronized(two) {}
}
每个对象具有锁定可以在其上同步:
最终对象锁=新的对象() 同步(锁定){。 ..}
如果你想同步整个方法,你不能说哪个对象,所以它总是“this”对象。
同步FOO(){....}
锁定的第一种方法是更好的,通过的方式。
建议不要将每种方法都锁定为this
,因为它在大多数情况下降低了并发性。所以建议使用锁解除其中只需要保护的代码的特定部分保存在同步块。
这是一种在Java Concurrency in Practice中很好解释的做法。但是请注意,只有当您具有线程的一些基本经验时,本书才有用。
一些掘金要记住:
- 不要过度使用同步
- 使用方法级同步仅当整个方法需要被保护
-
使用不同的锁来保护两个不相关的实体,这将增加并发的机会。或者为了读写两个不相关的实体,线程将阻塞在同一个锁上。
public void incrementCounter1(){ synchronized(lockForCounter1){ counter1++; } } public void incrementCounter2(){ synchronized(lockForCounter2){ counter2++; } }
从concurrency教程中,Synchronized methods部分:
为了使同步的方法,只需将同步关键字添加到它的声明:
public class SynchronizedCounter {
private int c = 0;
public synchronized void increment() {
c++;
}
public synchronized void decrement() {
c--;
}
public synchronized int value() {
return c;
}
}
如果count是Syn的一个实例chronizedCounter,然后使得这些方法同步有两个作用:
首先,它是不可能的同一对象上同步方法交织两个调用。当一个线程正在执行一个对象的同步方法时,所有其他线程将调用相同对象块(挂起执行)的同步方法,直到第一个线程完成对象。第二,当一个同步方法退出时,它会自动建立一个发生之前的关系,以及任何后续调用同步对象的同一个对象。这保证了对所有线程都可见的对象状态的更改。
简单地说,这是在Java中同步是如何工作的。
你不必指定哪个对象锁定了同步方法,因为它总是被'this'锁定(我相信)。
对于实例方法是正确的,对于锁定类对象的静态方法。
为什么你不能阻止一个非静态方法的对象不是'this'?
需要注意的是:
public synchronized void increment() {
c++;
}
等同于行为:
public void increment() {
synchronized(this) {
c++;
}
}
在这段代码,你可以用任何你希望的对象替换this
。
为什么你必须指定阻止同步代码的对象?
有些人,我们称之为关键,代码块只能按顺序运行,但在不受控制的并发环境中,它可能会并行运行。这就是为什么存在同步机制。
因此,我们可以把这样的代码:
- 代码安全并行地运行(默认情况下)
- 有要同步的代码(必须以某种方式标明)
该标记通过关键字和相应的锁定对象进行。
如果您有两个不同的关键代码块不能一起运行,它们都会有synchronized关键字,并且假设它们具有相同的锁定对象。
当第一个块正在执行时,锁定对象变为“锁定”。如果在该时间期间所述第二块需要得到执行,该代码块的第一命令是:
synchronized(lock) {
但锁定对象处于锁定状态,因为第一个块正在执行。第二个块的执行停止在该语句上,直到第一个块完成执行,并解锁锁定对象的状态。然后第二个块可以继续执行(并再次锁定锁定对象)。
该机制被称为mutual exclusion,而lock是一个与Java编程语言无关的通用概念。
“锁对象锁定”过程的详细信息可以在here找到。
我觉得你的两个问题实际上是一样的。假设您想要在多个线程之间同步一个对象a的方法m,您需要一个线程可以与之通信的公共基础系统或通道,这实际上是对象锁提供的,因此当您想要在某个对象的方法中同步时不需要另一个对象锁来做到这一点,因为你访问的对象本身具有这个锁,这就是lanuage设计的方式和原因。
虽然同步一个块不是一回事,但除了这个对象本身,线程可以拥有不同的通话基础,例如,可以为同步块设置同一个对象作为同步对象锁,因此此类的所有对象都可以在该区块同步!
谢谢,但我不知道这是如何回答我的两个问题。我不明白为什么在锁定方法和锁定代码之间存在不一致,即在同步代码时必须指定锁定对象。你能修改你的答案吗?再次感谢。 – w0051977 2013-04-07 08:59:26