java同步静态方法:锁定对象或类

2mbi3lxu  于 2021-07-03  发布在  Java
关注(0)|答案(8)|浏览(328)

java文档说明:
在同一对象上对同步方法的两次调用不可能交错。
这对于静态方法意味着什么?由于静态方法没有关联的对象,synchronized关键字会锁定类而不是对象吗?

ars1skjm

ars1skjm1#

对于那些不熟悉的静态同步方法锁定在类对象上的人,例如,对于string class,它的string.class,而示例同步方法锁定在java中由“this”关键字表示的对象的当前示例上。由于这两个对象都是不同的,它们有不同的锁,因此当一个线程执行静态同步方法时,java中的另一个线程不需要等待该线程返回,而是将获取表示为byte.class literal的单独锁并进入静态同步方法。

muk1a3rh

muk1a3rh2#

只是为了给奥斯卡的作品增加一点细节(令人愉快的简洁!)答:java语言规范的相关部分是8.4.3.6,“synchronized methods”:
同步方法获取监视器(§17.1)执行前。对于类(静态)方法,使用与该方法的类的类对象关联的监视器。对于示例方法,使用与此关联的监视器(为其调用方法的对象)。

roqulrg3

roqulrg33#

请看一下有关内部锁和同步的oracle文档页
您可能想知道调用静态同步方法时会发生什么,因为静态方法与类而不是对象相关联。在这种情况下,线程获取与类关联的类对象的内在锁。因此,对类的静态字段的访问是由一个锁控制的,该锁不同于类的任何示例的锁。

dgtucam1

dgtucam14#

下面的例子让类和对象锁更加清晰,希望下面的例子也能帮助其他人:)
例如,我们有以下方法一个获取类,另一个获取对象锁:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

所以,现在我们可以有以下场景:
当使用相同对象的线程尝试访问 objLockstaticLock 方法相同的时间(即两个线程都试图访问相同的方法)

Thread-0 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4

当使用相同对象的线程尝试访问 staticLock 以及 objLock 方法相同(尝试访问不同的方法)

Thread-0 0
Thread-1 0
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-1 3
Thread-0 3
Thread-0 4
Thread-1 4

当使用不同对象的线程尝试访问 staticLock 方法

Thread-0 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4

当使用不同对象的线程尝试访问 objLock 方法

Thread-0 0
Thread-1 0
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-1 3
Thread-0 3
Thread-0 4
Thread-1 4
b4qexyjb

b4qexyjb5#

由于静态方法没有关联的对象,synchronized关键字会锁定类而不是对象吗?
是。:)

ikfrs5lh

ikfrs5lh6#

静态方法也有一个关联的对象。它属于jdk工具箱中的class.class文件。当.class文件加载到ram中时,class.class会创建一个名为template object的示例。
例如:-当您尝试从现有的customer类创建对象时,例如

Customer c = new Customer();

customer.class加载到ram中。此时,jdk工具箱中的class.class创建了一个名为template object的对象,并将该customer.class加载到该模板对象中。该customer.class的静态成员将成为该模板对象中的属性和方法。
所以静态方法或属性也有一个对象

arknldoa

arknldoa7#

除非实现g(),如下所示:

g() {
    synchronized(getClass()) {
        ...
    }
}

当我想在对象的不同示例之间实现互斥(例如,在访问外部资源时需要互斥)时,我发现这个模式也很有用。

iyfjxgzm

iyfjxgzm8#

有一点你必须小心(几个程序员通常会落入这个陷阱)那就是同步的静态方法和同步的非静态方法之间没有联系,即:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

主要内容:

A a = new A();

线程1:

A.f();

螺纹2:

a.g();

f()和g()不同步,因此可以完全并发执行。

相关问题