如果我在同一个类中有2个同步方法,但每个方法访问不同的变量,那么2个线程可以同时访问这两个方法吗?锁是否发生在对象上,或者它是否与synchronized方法中的变量一样具体?
例:
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
}
2个线程可以同时访问同一个X类实例,执行 x.addA(
)和 x.addB()
吗?
10 回答
这可能不起作用,因为从Integer到int和反向的装箱和自动装箱依赖于JVM,并且如果它们在-128和127之间,则很可能将两个不同的数字散列到相同的地址 .
如果您将方法声明为同步(正如您通过键入
public synchronized void addA()
那样),则在 whole 对象上进行同步,因此从同一对象访问不同变量的两个线程无论如何都会相互阻塞 .如果您希望一次仅同步一个变量,那么两个线程在访问不同变量时不会相互阻塞,您可以在
synchronized ()
块中单独同步它们 . 如果a
和b
是对象引用,您将使用:但由于他们是原始人,你不能这样做 .
我建议你改用AtomicInteger:
在方法声明上同步是这样的语法糖:
在静态方法上,它是语法糖:
我认为如果Java设计者知道现在对同步的理解,他们就不会添加语法糖,因为它往往会导致并发性的不良实现 .
访问的锁是在对象上,而不是在方法上 . 在该方法中访问哪些变量是无关紧要的 .
将“synchronized”添加到方法意味着运行代码的线程必须在继续之前获取对象的锁定 . 添加“静态同步”意味着运行代码的线程必须在继续之前获取类对象的锁定 . 或者,您可以将代码包装在一个块中,如下所示:
这样您就可以指定必须获取其锁定的对象 .
如果要避免锁定包含对象,可以选择:
using synchronized blocks that specify different locks
使a和b原子(使用java.util.concurrent.atomic)
From the Java SE essentials on synchronized methods:
来自Java SE essentials on synchronized blocks:
(强调我的 . )
你有2个变量no-interleaved . 因此,您希望同时访问来自不同线程的每个线程 . 你需要在对象类本身上定义锁定,而不是像下面的类Object那样定义锁定(例如来自第二个Oracle链接):
来自oracle文档link
使方法同步有两个影响:
请查看本文档page以了解内部锁和锁定行为 .
This will answer your question: On same object x , you can't call x.addA() and x.addB() at same time when one of the synchronized methods execution is in progress.
您可以执行以下操作 . 在这种情况下,您使用a和b上的锁来同步而不是锁定“this” . 我们不能使用int,因为原始值没有锁,所以我们使用Integer .
如果您有一些未同步的方法,并且正在访问和更改实例变量 . 在你的例子中:
任意数量的线程当其他线程在同一对象的synchronized方法中并且可以更改实例变量时,可以同时访问这些非同步方法 . 例如: -
您需要避免非同步方法正在访问实例变量并更改它的情况,否则无法使用同步方法 .
在以下场景中: -
只有一个线程可以是addA或addB方法,但同时任何数量的线程都可以进入changeState方法 . 没有两个线程可以同时输入addA和addB(因为对象级别锁定)但同时任何数量的线程都可以进入changeState .
这个例子(尽管不是很好)可以提供对锁定机制的更多了解 . 如果incrementA是 synchronized ,incrementB是 not synchronized ,则incrementB将尽快执行,但如果incrementB也是 synchronized ,则在incrementB完成其工作之前,它必须为incrementA完成'wait' .
两个方法都被调用到单个实例 - 对象,在这个例子中它是:job,而'competing'个线程是aThread和main .
尝试使用incrementB中的' synchronized ',如果没有它,你会看到不同的结果 . 如果incrementB是' synchronized ',那么它必须等待incrementA()完成 . 每个变体运行几次 .
是的,它会阻止另一个方法,因为synchronized方法适用于指向的 WHOLE 类对象....但无论如何它会阻止其他线程执行 ONLY ,同时执行任何方法addA或addB进入,因为当它完成...一个线程将 FREE 对象,另一个线程将访问另一个方法,等等完美工作 .
我的意思是“同步”正是为了阻止其他线程在特定代码执行时访问另一个线程 . 所以这个代码最终会工作得很好 .
最后要注意的是,如果存在'a'和'b'变量,而不仅仅是一个唯一变量'a'或其他任何名称,则无需同步此方法,因为它可以非常安全地访问其他var(其他内存)地点) .
也会工作