我们可以在 java 中的 class 中有多个静态锁吗?

Can we have multiple static locks in a class in java

我有多个方法,我想对其进行静态锁定,这样没有两个对象可以访问一个方法,但同时不同的方法不会被这些对象锁定,并且可以 运行 独立。

class A {
    private static final A lock1 = new A();
    private static final B lock2 = new B();

    public void method1() {
        synchronized (lock1) {
            // do something
        }
    }

    public void method2() {
        synchronized (lock2) {
            // do something
        }
    }
}

现在我希望这两个方法在被锁定时相互独立,但同时我希望相同 class 的多个实例被锁定在一个方法中。

如何实现?通过使用不同的 class ?仅此即可实现吗?

首先,这就足够了:

private static final Object lock1 = new Object();
private static final Object lock2 = new Object();

那么,通过你的实现,method1method2是相互独立的,但是method1method2只有一个实例可以运行在 A 的所有实例中。如果要允许 A 的不同并发实例,以便不同实例的 method1method2 可以并发 运行,只需声明没有 static 的锁即可。 =29=]

换句话说:如果 a1a2A 的实例:

  • with static 锁,如果 a1.method1 是 运行ning,a2.method1 不能被另一个线程 运行
  • 没有static,a1.method1只能被一个线程运行。 a1.method1a2.method1 可以同时 运行。

静态锁
如果锁定的对象位于静态字段中,则该特定 Class 的所有实例都将共享该锁。这意味着如果从那个 class 创建的一个对象正在访问那个 static 锁,那么从那个 class 创建的另一个对象不能访问那个锁。

非静态锁
如果 class 有一个非静态的锁,那么每个实例都会有自己的锁,所以只有对同一个对象的方法调用才会相互锁定。

作为使用静态锁对象的例子:

  • 线程 1 调用 obj01.doSomething()
  • 线程 2 调用 obj01.doSomething(),必须等待线程 1 完成
  • 线程 3 调用 obj02.doSomething(),也必须等待线程 1(可能还有线程 2)完成。

当您使用 非静态锁 对象时:

  • 线程 1 调用 obj01.doSomething()
  • 线程 2 调用 obj01.doSomething(),必须等待线程 1 完成
  • 线程 3 调用 obj02.doSomething(),它可以继续,不关心线程 1 和 2,因为这是一个新对象,它不依赖于 class.

非静态锁基本上是对象级锁。静态锁是class级锁

对象级锁定
Java 中的每个对象都有一个唯一的锁。如果线程想要在给定对象上执行同步方法,首先它必须获得该对象的锁。一旦线程获得锁,就可以在该对象上执行任何同步方法。一旦方法执行完成自动线程释放锁。

public class Example implements Runnable {

    @Override
    public void run() {
        objectLock();
    }
    public void objectLock() {
        System.out.println(Thread.currentThread().getName());
        synchronized(this) {
            System.out.println("Synchronized block " + Thread.currentThread().getName());
            System.out.println("Synchronized block " + Thread.currentThread().getName() + " end");
        }
    }
    public static void main(String[] args) {
        Example test1 = new Example();
        Thread t1 = new Thread(test1);
        Thread t2 = new Thread(test1);
        Example test2 = new Example();
        Thread t3 = new Thread(test2);
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

输出将是,

t1
t3
Synchronized block t1
t2
Synchronized block t1 end
Synchronized block t3
Synchronized block t2
Synchronized block t3 end
Synchronized block t2 end

Class 等级锁
Java 中的每个 class 都有一个唯一的锁,它只不过是 class 级别的锁。如果一个线程要执行一个静态同步方法,那么这个线程就需要一个class级的锁。一旦一个线程获得了 class 级别的锁,那么它就可以执行该 class 的任何静态同步方法。一旦方法执行完成自动线程释放锁。

public class Example implements Runnable {

    @Override
    public void run() {
        classLock();
    }
    public static void classLock() {
        System.out.println(Thread.currentThread().getName());
        synchronized(Example.class) {
            System.out.println("Synchronized block " + Thread.currentThread().getName());
            System.out.println("Synchronized block " + Thread.currentThread().getName() + " end");
        }
    }
    public static void main(String[] args) {
        Example test1 = new Example();
        Thread t1 = new Thread(test1);
        Thread t2 = new Thread(test1);
        Example test2 = new Example();
        Thread t3 = new Thread(test2);
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

输出如下所示,

t1
t3
t2
Synchronized block t1
Synchronized block t1 end
Synchronized block t2
Synchronized block t2 end
Synchronized block t3
Synchronized block t3 end

当前情况

在这里你有两个方法,如果一个方法使用一个锁访问而另一个方法使用另一个锁,在你的实现中你可以有两个对象使用彼此的方法但永远不会使用相同的方法。

obj01.method01();
obj02.method02();

这是可能的,但不是这样

obj01.method01();
obj02.method01();

obj02必须等到obj01完成这个方法。

锁不适用于方法。锁用于 data。使用互斥锁的全部目的是确保不同线程始终看到某些共享数据的一致视图。

您的代码示例显示了两个锁,但没有显示锁应该保护的 数据。这个比较好:

class Example {
    // R-State variables
    private final Object lockR = new Object();
    private A a = ...;
    private B b = ...;
    private C c = ...;

    // G-State variables
    private final Object lockG = new Object();
    private Alpha alpha = ...;
    private Beta beta = ...;
    private Gamma gamma = ...;

    public void methodR() {
        synchronized (lockR) {
            // do something with a, b, and c.
        }
    }

    public void methodG() {
        synchronized (lockG) {
            // do something with alpha, beta, and gamma.
        }
    }
}

我的Exampleclass有两组独立的变量; abcalphabetagamma。每个独立组都有自己独立的锁。访问任何“R-State”变量的任何方法都应该是 synchronized (lockR)...,对于“G-State”变量和 lockG.

也是如此

如果一个方法需要同时访问两个组,那么它必须锁定两个锁。但是注意! 可能表明这两个群体并不是真正独立的。如果它们之间有任何依赖关系,那么真的应该只有一把锁。


另请注意,我从示例中删除了 static。那是一个纯粹无偿的改变。我讨厌static。你也应该厌恶它,但那是一个与锁定无关的不同主题。