2012-06-29 33 views
0

您好我有多种方法,我需要synchronized块在所有的方法是这样一类:同步块问题?

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,它不应该等待。

+0

如果这不是你想要的行为,你想什么'method2'去做?跳过块?然后同步不是你正在寻找... – brimborium

+0

我想其他线程只有等待,如果调用相同的方法..喜欢如果两个线程类mehod1所以第二个线程应该等待。但如果第二个线程调用method2,它不应该等待。 – Harinder

+0

向下投票 - 非常本地化的问题,即使作者在问题中提出这个问题,答案也非常明显。 – Romain

回答

4

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

+0

所以你的意思是说,如果我有大约20种方法?我应该有20个互斥体对象?没有其他解决方法吗? – Harinder

+0

那么你可以声明一个包含20个对象的数组,比如'Object [] mutexes = new Object [20];'并为每个方法使用不同的索引,所以你不需要声明20个类成员。 – Tudor

+0

@ Dennis:由于每个线程都有自己的私有堆栈,因此在本地声明它们会使每个线程看到不同的互斥锁,这将是无用的。他们需要全球可见。 – Tudor

4

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

+0

所以你的意思是说,如果我有大约20种方法?我应该有20个互斥体对象?没有其他解决方法吗? – Harinder

2

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

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

如果你有很多方法,你也可以将它们打包在一个数组中。

+0

这些也可以是局部变量或他们不会工作?他们必须是成员变量? – Harinder

+1

@Dennis局部变量不会工作,因为每个方法的调用都有自己的局部变量。 –

+1

@ Dennis它们不能是局部变量,因为在每次方法调用时都会创建新变量。同步不会那样工作... – brimborium

2

如果您想实现这个目标并对它们进行同步,您必须为每个方法调用使用不同的监视器对象(代码中的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 
    } 
} 

请注意,如果您同步在每个方法的基础,但每种方法从访问同一个对象(obj你的情况)​​块,对该特定对象的访问仍然不是线程安全的。

的另一个选项是初始化在构造函数中的所有互斥锁代替点播在getMutex()方法创建它们的:

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

您需要**'getMutex(int)'方法是'synchronized'(或对'mutexes'使用同步的双重检查),或者两个调用可以获得两个不同的互斥锁。 (A检查,A分配互斥体,B其他检查,A分配互斥体,B分配互斥体,KABOOOM)。 – Romain

+0

@Romain:你说得对,我已经更新了这个例子。另一个选择是在方法调用之前初始化所有的互斥体(例如在'Test2'构造函数中),然后根本不需要'null'检查。 – buc

+0

是的。像private private Object [] mutexes = {new Object(),new Object()};'会很好地完成这项工作。 – Romain