我有许多共享变量 x,y,z,所有这些都可以在两个不同线程中运行的两种不同方法中修改。(比如线程 1 中的方法 1 和线程 2 中的方法 2)。如果我将这两个方法声明为 synchronized ,是否保证变量 x,y 和 z 的一致性。或者我应该单独对每个变量使用锁定?
4 回答
是的,您的方法将保证一致性,假设这些变量都是私有的并且在两个同步方法之外不被访问(读取或写入)。
请注意,如果您在同步块之外读取这些变量,那么您可能会得到不一致的结果:
class Foo {
private int x;
public synchronized void foo() {
x = 1;
}
public synchronized void bar() {
x = 2;
}
public boolean baz() {
int a = x;
int b = x;
// Unsafe! x could have been modified by another thread between the two reads
// That means this method could sometimes return false
return a == b;
}
}
编辑:更新以解决您对静态变量的评论。
每个类都应该拥有自己的数据。如果类A
允许直接访问变量(通过将其公开),那么它不拥有自己的数据,并且很难强制执行线程安全。
如果你这样做:
class A {
private static int whatever;
public static synchronized int getWhatever() {
return whatever;
}
public static synchronized void setWhatever(int newWhatever) {
whatever = newWhatever;
}
}
那么你会没事的。
请记住,这synchronized
会对单个对象强制执行互斥锁。对于同步方法,它是this
(或静态方法的 Class 对象)。其他对象上的同步块不会干扰。
class A {
public synchronized void doSomething() {...}
}
class B {
public synchronized void doSomethingElse() {...}
}
调用doSomething
不会等待调用,doSomethingElse
因为它们在不同的对象上同步:在这种情况下,相关的实例A
和B
. doSomething
同样,对不同实例的两次调用A
也不会干扰。
我强烈建议您看看Java Concurrency in Practice。这是一本很好的书,它解释了 Java 线程和内存模型的所有微妙之处。
是的,它将是一致的。
同步方法在执行之前获取监视器(第 17.1 节)。对于类(静态)方法,使用与方法类的 Class 对象关联的监视器。对于实例方法,使用与 this(调用该方法的对象)关联的监视器。
看看这个链接
注意:- 你必须小心的一点(一些程序员通常陷入这个陷阱)是同步的静态方法和同步的非静态方法之间没有联系
当您同步方法时:
- 如果 method 是
static
,将在class
对象上获取锁 - 如果 method 是
non-static
,则将对该instance
对象进行锁定。
只要锁一次只被一个线程占用,是的,做你想做的事情是一致且安全的。
这是主观的。行为取决于您实例化线程的方式。如果两个线程在包含这些方法的类的同一实例上调用同步化方法,它们将阻塞。如果每个线程实例化一个包含方法的类的新对象,它们将不会阻塞,因为在该类的两个不同实例上会有两个锁。