我有一些共享变量x,y,z,所有这些变量都可以在两个不同的线程中运行两种不同的方法进行修改。(比如线程1中的方法1和线程2中的方法2)。如果我将这两个方法声明为synchronized,它是否保证变量x,y和z的一致性。或者我应该在每个变量上单独使用锁?
答案 0 :(得分:2)
是的,您的方法将保证一致性,假设这些变量都是私有的,并且在两个同步方法之外不被访问(读取或写入)。
请注意,如果您在同步块之外读取这些变量,则可能会得到不一致的结果:
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线程和内存模型的所有细微之处。
答案 1 :(得分:1)
是的,它会保持一致。
synchronized方法在执行之前获取监视器(第17.1节)。 对于类(静态)方法,与类关联的监视器 使用方法类的对象。对于实例方法, 与此关联的监视器(方法所针对的对象) 使用了。
查看此link
注意: - 您需要注意的一点(一些程序员通常属于该陷阱)是同步静态方法和同步非静态方法之间没有链接
答案 2 :(得分:1)
同步方法时:
static
,则锁定将在class
对象non-static
,则会对instance
对象进行锁定。只要锁定一次仅由一个线程执行,是的,按照您的意图执行操作是一致且安全的。
答案 3 :(得分:0)
这是主观的。行为取决于您实例化线程的方式。如果两个线程在包含这些方法的类的同一实例上调用同步方法,则它们将阻塞。如果每个线程实例化包含方法的类的新对象,则它们不会阻塞,因为在该类的两个不同实例上将存在两个锁。