【问题标题】:Synchronized block issue?同步块问题?
【发布时间】:2012-06-29 12:35:11
【问题描述】:

您好,我有一个包含多个方法的类,其中我需要在所有方法中使用同步块,如下所示:

public class Test2 {
    private Object mutex=new Object();
    private OtherClass obj=new OtherClass();

    public void method1(){
        //do some stuff
        synchronized (mutex) {
            obj.//some method
            //do some stuff
        }
        //do other stuff
    }

    public void method2(){
        //do some stuff
        synchronized (mutex) {
            obj.//some method
            //do some stuff
        }
        //do other stuff
    }

    public void method3(){
        //do some stuff
        synchronized (mutex) {
            obj.//some method
            //do some stuff
        }
        //do other stuff
    }

    public void method4(){
        //do some stuff
        synchronized (mutex) {

            obj.//some method
            //do some stuff
        }
        //do other stuff
    }
}

我正在使用互斥锁来同步块,所以如果正在使用 method1 会发生什么,另一个 method2 同步块等待直到流从 method1 的同步块中流出。

我不希望这种情况发生,那我该怎么办?我知道,因为我对所有方法都使用互斥锁,所以它锁定了 method2 同步块。我想知道我应该怎么做才能删除它?我应该为每个要使用的方法创建成员变量,还是有其他方法可以解决这个问题?

我希望其他线程只有在调用相同的方法时才等待。就像两个线程类 mehod1 一样,第二个线程应该等待。但如果第二个线程调用 method2 它不应该等待。

【问题讨论】:

  • 如果这不是您想要的行为,您希望method2 做什么?跳过街区?那么同步的不是你要找的……
  • 我希望其他线程只有在调用相同的方法时才等待。就像两个线程类 mehod1 一样,所以第二个线程应该等待。但如果第二个线程调用 method2 它不应该等待。
  • 投反对票 - 非常本地化的问题,即使作者在问题中提出了答案,答案也非常明显。
  • @Romain 好吧,他问是否有更好的方法。答案对你来说可能是微不足道的,但假设答案对每个人来说都是显而易见的,这是不正确的......
  • @brimborium 如果 Google 和 StackOverflow 还没有以某种方式回答这个问题十亿次,那么假设是不正确的。问题是他们这样做了。

标签: java multithreading synchronization


【解决方案1】:

从您的评论来看,我假设您想要按方法同步而不是按对象同步。在这种情况下,最简单的方法是为每个方法声明一个单独的监视器对象,即mutex1mutex2 等。

【讨论】:

  • 所以你的意思是如果我有大约 20 种方法?我应该有 20 个互斥对象?没有其他办法解决这个问题吗?
  • 您可以声明一个包含 20 个对象的数组,例如 Object[] mutexes = new Object[20];,并为每个方法使用不同的索引,因此您不需要声明 20 个类成员。
  • @Dennis:由于每个线程都有自己的私有堆栈,因此在本地声明它们将使每个线程看到不同的互斥体,这将是无用的。它们需要在全球范围内可见。
  • 嘿但是 Object[] mutexes = new Object[20];导致空指针..??使用它的索引后?
  • @Dennis 你必须初始化数组
【解决方案2】:

您应该在 method2 方法中使用另一个 mutext。

【讨论】:

  • 所以你的意思是如果我有大约 20 种方法?我应该有 20 个互斥对象?没有其他办法解决这个问题吗?
【解决方案3】:

只需为每种方法使用不同的监视器。

public class Test2 {
    private Object mutex1 = new Object(), mutex2 = new Object();
    private OtherClass obj=new OtherClass();

    public void method1() {
        //do some stuff
        synchronized (mutex1) {
            obj.//some method
            //do some stuff
        }
        //do other stuff
    }

    public void method2() {
        //do some stuff
        synchronized (mutex2) {
            obj.//some method
            //do some stuff
        }
        //do other stuff
    }
}

如果方法很多,也可以打包成一个数组。

【讨论】:

  • 这些也可以是局部变量还是不起作用?它们必须是成员变量?
  • @Dennis 局部变量不起作用,因为该方法的每次调用都会获得自己的局部变量。
  • @Dennis 它们不能是局部变量,因为它们会在每次方法调用时创建新的。同步不会那样工作......
【解决方案4】:

如果您想实现这一点并与它们同步,您必须为每个方法调用使用不同的监视器对象(代码中的mutex)。如果你有很多方法,你可以使用某种集合来保存你的互斥对象:

public class Test2 {
    private Object[] mutexes=new Object[2];
    private OtherClass obj=new OtherClass();

    private synchronized Object getMutex(int i) {
        if(mutexes[i] == null) {
            mutexes[i] = new Object();
        }
        return mutexes[i];
    }

    public void method1(){
        //do some stuff
        synchronized (getMutex(1)) {
           //do some stuff
        }
        //do other stuff
    }

    public void method2(){
        //do some stuff
        synchronized (getMutex(2)) {
            //do some stuff
        }
        //do other stuff
    }
}

请注意,如果您基于每个方法进行同步,但每个方法都从 synchronized 块访问相同的对象(在您的情况下为 obj),那么对该特定对象的访问仍然不是线程安全的。

另一种选择是在构造函数中初始化所有互斥体,而不是在 getMutex() 方法中按需创建它们:

public Test() {
    for(int i = 0; i < mutexes.length()) {
        mutexes[i] = new Object();
    }
}

【讨论】:

  • 需要getMutex(int) 方法设为synchronized(或对mutexes 使用同步复查),否则两次调用可以获得两个不同的互斥体。 (A 检查,A 分配互斥体,B 其他检查,A 分配互斥体,B 分配互斥体,KABOOOM)。
  • @Romain:你说得对,我已经更新了这个例子。另一种选择是在方法调用之前初始化所有互斥锁(例如,在Test2 构造函数中),然后null-check 根本不需要。
  • 确实如此。像private final Object[] mutexes = {new Object(), new Object()}; 这样的东西会很好地完成这项工作。
猜你喜欢
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 2012-07-08
  • 2011-07-15
  • 2015-05-03
  • 2012-11-01
  • 2011-09-10
  • 1970-01-01
相关资源
最近更新 更多