对象上的Java同步方法锁,还是方法?
如果在同一个类中有两个同步方法,但每个方法访问不同的变量,那么两个线程可以同时访问这两个方法吗?锁是发生在对象上,还是与同步方法中的变量一样具体 例如:对象上的Java同步方法锁,还是方法?,java,multithreading,thread-safety,locking,synchronized,Java,Multithreading,Thread Safety,Locking,Synchronized,如果在同一个类中有两个同步方法,但每个方法访问不同的变量,那么两个线程可以同时访问这两个方法吗?锁是发生在对象上,还是与同步方法中的变量一样具体 例如: class X { private int a; private int b; public synchronized void addA(){ a++; } public synchronized void addB(){ b++; } } 两个线程能否
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
}
两个线程能否同时访问类X的同一个实例执行
X.addA(
)和X.addB()
?访问的锁在对象上,而不是在方法上。在方法中访问哪些变量是无关的
向方法中添加“synchronized”意味着运行代码的线程必须在继续之前获取对象的锁。添加“static synchronized”意味着运行代码的线程必须在继续之前获得类对象上的锁。或者,您可以将代码包装在块中,如下所示:
public void addA() {
synchronized(this) {
a++;
}
}
以便您可以指定必须获取其锁的对象
如果要避免锁定包含的对象,可以选择:
- 使a和b原子化(使用java.util.concurrent.atomic)
public void addA() {
synchronized (this) {
a++;
}
}
ClassA {
public static void addA() {
synchronized(ClassA.class) {
a++;
}
}
在静态方法中,这是语法上的糖分:
public void addA() {
synchronized (this) {
a++;
}
}
ClassA {
public static void addA() {
synchronized(ClassA.class) {
a++;
}
}
我认为,如果Java设计人员当时知道现在对同步的理解,他们就不会添加语法糖,因为它通常会导致并发性的糟糕实现。如果您将该方法声明为已同步(就像您通过键入
public synchronized void addA()
所做的那样)您可以对整个对象进行同步,因此两个线程访问来自同一对象的不同变量时会相互阻塞
如果您希望一次只同步一个变量,这样两个线程在访问不同变量时不会互相阻塞,那么您可以在synchronized()
块中分别对它们进行同步。如果a
和b
是对象引用,您将使用:
public void addA() {
synchronized( a ) {
a++;
}
}
public void addB() {
synchronized( b ) {
b++;
}
}
但既然它们是原始的,你就不能这么做
我建议您改用AtomicInteger:
您可以执行以下操作。在这种情况下,您使用a和b上的锁来同步,而不是“this”上的锁。我们不能使用int,因为原语值没有锁,所以我们使用Integer
class x{
private Integer a;
private Integer b;
public void addA(){
synchronized(a) {
a++;
}
}
public synchronized void addB(){
synchronized(b) {
b++;
}
}
}
这可能不起作用,因为从Integer到int的装箱和自动装箱以及viceversa依赖于JVM,如果两个不同的数字在-128到127之间,很可能会被散列到同一地址 如果您有一些不同步的方法,并且正在访问和更改实例变量。在您的示例中:
private int a;
private int b;
当其他线程处于同一对象的同步方法中时,任意数量的线程都可以同时访问这些非同步方法,并且可以更改实例变量。
例如:-
public void changeState() {
a++;
b++;
}
您需要避免非同步方法访问实例变量并对其进行更改的情况,否则就没有必要使用同步方法
在以下场景中:-
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
public void changeState() {
a++;
b++;
}
}
只有一个线程可以在addA或addB方法中,但同时任何数量的线程都可以进入changeState方法。没有两个线程可以同时输入addA和addB(因为对象级锁定),但是任何数量的线程都可以同时进入changeState。来自oracle文档 使方法同步有两种效果: 首先,同一对象上的两个同步方法调用不可能交错。当一个线程为一个对象执行同步方法时,调用同一对象块的同步方法的所有其他线程(暂停执行),直到第一个线程对该对象执行完毕 其次,当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立“发生在之前”关系。这保证了对对象状态的更改对所有线程都是可见的 请阅读此文档以了解内在锁和锁行为 这将回答您的问题:在同一个对象x上,当其中一个同步方法正在执行时,您不能同时调用x.addA()和x.addB()。这个示例(虽然不是很好)可以更深入地了解锁定机制。如果incrementA已同步,而incrementB未同步,则incrementB将尽快执行,但如果incrementB也已同步,则它必须“等待”incrementA完成,然后incrementB才能执行其工作 这两种方法都被调用到单个实例对象上,在本例中是:job,而“竞争”线程是aThread和main 尝试在incrementB中使用“synchronized”和不使用它,您将看到不同的结果。如果incrementB也是“synchronized”,则它必须等待incrementA()完成。每种变体运行几次
class LockTest implements Runnable {
int a = 0;
int b = 0;
public synchronized void incrementA() {
for (int i = 0; i < 100; i++) {
this.a++;
System.out.println("Thread: " + Thread.currentThread().getName() + "; a: " + this.a);
}
}
// Try with 'synchronized' and without it and you will see different results
// if incrementB is 'synchronized' as well then it has to wait for incrementA() to finish
// public void incrementB() {
public synchronized void incrementB() {
this.b++;
System.out.println("*************** incrementB ********************");
System.out.println("Thread: " + Thread.currentThread().getName() + "; b: " + this.b);
System.out.println("*************** incrementB ********************");
}
@Override
public void run() {
incrementA();
System.out.println("************ incrementA completed *************");
}
}
class LockTestMain {
public static void main(String[] args) throws InterruptedException {
LockTest job = new LockTest();
Thread aThread = new Thread(job);
aThread.setName("aThread");
aThread.start();
Thread.sleep(1);
System.out.println("*************** 'main' calling metod: incrementB **********************");
job.incrementB();
}
}
class LockTest实现可运行{
int a=0;
int b=0;
公共同步的无效增量A(){
对于(int i=0;i<100;i++){
这个.a++;
System.out.println(“Thread:+Thread.currentThread().getName()+”a:+this.a);
}
}
//尝试使用“synchronized”和不使用它,您将看到不同的结果
//如果incrementB也是“同步”的,那么它必须等待incrementA()完成
//公共无效增量b(){
公共同步的无效增量B(){
这是.b++;
System.out.println(“*******************增量B****************************”);
System.out.println(“Thread:+Thread.currentThread().getName()+”b:+this.b);
System.out.println(“*******************增量B********************************”
class X {
private int a;
private int b;
public void addA(){
a++;
}
public void addB(){
b++;
}}