当前位置: 首页 > 知识库问答 >
问题:

在java中,一个类中可以有多个静态锁吗

胡飞舟
2023-03-14

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

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

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

如何实现这一点?通过使用不同的类。仅仅这样做能达到目的吗?

共有3个答案

高增
2023-03-14

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

非静态锁
如果类有一个非静态锁,那么每个html" target="_blank">实例都有自己的锁,因此只有对同一对象的方法调用才会相互锁定。

例如,当您使用静态锁对象时:

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

湛宝
2023-03-14

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

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

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

我的< code>Example类有两组独立的变量;< code>a 、< code>b和< code>c、以及< code>alpha 、< code>beta和< code>gamma。每个独立的组都有自己独立的锁。任何访问“R状态”变量的方法都应该< code >同步(lockR)...,对于“G-State”变量和< code > locgg 也是如此。

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

另请注意,我从示例中删除了静态。这纯粹是无端的改变。我憎恶静态。你也应该憎恶它,但这是一个与锁定无关的不同主题。

松阳泽
2023-03-14

首先,这就足够了:

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

然后,通过您的实现,方法1方法2是相互独立的,但是方法1方法2的一个实例只能在A的所有实例中运行。如果您想允许A的不同并发实例,以便不同实例的方法1方法2可以并发运行,只需声明不带静态的锁即可。

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

  • 使用静态锁时,如果 a1.method1 正在运行,则 a2.method1 不能由另一个线程运行
  • 如果没有静态,a1.method1 只能由一个线程运行。a1.方法1a2.方法1 可以同时运行。
 类似资料:
  • 问题内容: 在Java文件中具有多个类的目的是什么? 编辑: 这可以通过在公共类内部创建内部类来实现,对吗? 问题答案: 是的,它可以。但是,每个文件只能有一个公共顶级类,并且公共顶级类必须与源文件具有相同的名称。 在一个源文件中包含多个类的目的是将相关的支持功能(内部数据结构,支持类等)与主要的公共类捆绑在一起。请注意,不要这样做总是可以的-唯一的影响就是代码的可读性。

  • 本文向大家介绍一个try块在Java中可以有多个catch块吗?,包括了一个try块在Java中可以有多个catch块吗?的使用技巧和注意事项,需要的朋友参考一下 是的,单个try块可以有多个catch块。 示例 以下Java程序包含一个数字数组(显示)。从用户那里,它接受此数组中的两个位置,然后将第一个位置的数字除以第二个位置的数字。 输入值时- 如果选择的位置不在显示的数组中,则抛出Array

  • 问题内容: 我正在考虑构建一个非常大的Java类,Java类可以具有的方法数量是否有限制?它可以用于数百万种方法吗? 更新:是的,目的是制作“神”类。 问题答案: 根据Java类文件规范,限制为 65535 : 4.10 Java虚拟机的局限性 文件格式隐含了Java虚拟机的以下限制: 一个类或接口可以声明的方法的数量由该结构项的大小限制为65535 (第4.1节)。请注意,结构项的值不包括从超类

  • 我在一个类中有多个同步的静态方法。 现在只允许一个线程执行类中的任何同步函数。这是不有效的,因为这些函数彼此独立并且可以并行运行。我如何才能使它们彼此独立,但每个方法只允许一个线程,而对类的更改最少。

  • 问题内容: div标签可以有两个类吗? 我正在使用twitter bootstrap,我想使用两个预定义的类。 一个是我想在导航栏中使用的类。 在不覆盖CSS的情况下,在html中解决此问题的最佳方法是什么。 问题答案: 当然,一个div可以具有所需的任意多个类(这通常与引导程序和HTML有关): 只需按空格分隔类。 另外: 请记住,一些引导程序类应该用于相同的东西,但是在不同情况下(例如,对齐类

  • 一个trait中的静态函数可以调用同一trait中的另一个静态函数吗?假设我有以下特点: 那不行。代码不能在这里编译。 此外,没有类型让我使用完全限定的语法,如