【问题标题】:Can we have multiple static locks in a class in java我们可以在java中的一个类中有多个静态锁吗
【发布时间】:2021-10-02 22:36:56
【问题描述】:

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

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
        }
    }
}

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

如何做到这一点?通过使用不同的类?这样做可以实现吗?

【问题讨论】:

  • 您当然可以通过这种方式使用锁。如果您确实希望这些方法完全独立,那么您的做法是正确的。如果您能给我们举个例子说明您正在尝试做什么,我们或许可以为您提供进一步的建议。

标签: java multithreading synchronization thread-safety java-threads


【解决方案1】:

首先,这就足够了:

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

然后,通过您的实现,method1method2 彼此独立,但只有一个 method1method2 实例可以在所有 A 实例中运行。如果要允许A的不同并发实例,使不同实例的method1method2可以同时运行,只需声明不带static的锁即可。

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

  • 带有static锁,如果a1.method1正在运行,a2.method1不能被另一个线程运行
  • 没有静态,a1.method1 只能由一个线程运行。 a1.method1a2.method1 可以同时运行。

【讨论】:

    【解决方案2】:

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

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

    以使用静态锁对象为例:

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

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

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

    非静态锁基本上是对象级锁。静态锁是类级别的锁

    对象级别锁定
    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
    

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

    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 完成该方法。

    【讨论】:

      【解决方案3】:

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

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

      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.
              }
          }
      }
      

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

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


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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-07
        • 2015-12-05
        • 2014-05-14
        • 1970-01-01
        • 2011-03-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多