Java在对象上同步

时间:2011-10-21 15:23:09

标签: java methods locking synchronize

我有一个问题。如何从同一个类同步两个不同的方法以锁定同一个对象?这是一个例子:

public class MyClass extends Thread implements Observer{
  public List<AnotherClass> myList = null;

  public MyClass(List<AnotherClass> myList){
    this.myList = myList;
  }

  public void run(){
    while(true){
       //Do some stuff 
       myList.add(NotImportantElement);
    }
  }

  public void doJob{
    for(int i=0; i<myList.size; i++){
      ElementClass x = myList.get(i);
      //Do some more stuff
    }
  }
}

问题是如何在执行doJob时停止run()访问myList,反之亦然?

想象一下:我启动线程并开始向列表中添加元素。在随机的时刻,我从另一个持有对我的线程的引用的类中调用doJob()。

我该怎么做锁?谢谢!

L.E。

好的,我理解了锁的概念,但现在我还有另一个问题。

假设我有一个包含public static myList的类,并且只有该类的一个实例。在那个实例中,我创建nThread个实例,它们接受该列表的每个元素并用它做一些事情。

现在,在特定时刻,myList已更新。那些已经在处理myList元素的线程会发生什么?在更新时如何锁定myList上的访问权限?

5 个答案:

答案 0 :(得分:5)

注意:此代码假设您只有一个MyClass实例。根据你的帖子,听起来就是这样。

public class MyClass extends Thread implements Observer{
  private List<AnotherClass> myList = null;
  private Object lock = new Object();

  public MyClass(List<AnotherClass> myList){
    this.myList = new ArrayList(myList);
  }

  public void run(){
    while(true){
       //Do some stuff 
       synchronized(lock) {
        myList.add(NotImportantElement);
       }
    }
  }

  public void doJob{
    synchronized(lock) {
      for(int i=0; i<myList.size; i++){
        ElementClass x = myList.get(i);
        //Do some more stuff
      }
    }
  }
}

编辑:已添加制作List的副本,以便外部实体无法按照JB Nizet更改列表

编辑2:将变量设为私有,以便其他人无法访问

答案 1 :(得分:4)

你可以:

  1. 同时声明rundoJob synchronized。这将使用this作为锁;
  2. 将列表声明为final并在其上进行同步。这将使用list作为锁。将锁定字段声明为final是一种很好的做法。这样,您的类的某些方法可以在一个对象上同步,而其他方法可以使用其他对象进行同步。这减少了锁争用,但增加了代码复杂性;
  3. 引入显式java.util.concurrent.locks.Lock变量并使用它的方法进行同步。这将提高代码灵活性,但也会增加代码复杂性;
  4. 不要完全显式同步,而是使用JDK的一些线程安全数据结构。例如,BlockingQueueCopyOnWriteArrayList。这将降低代码复杂性并确保线程安全。
  5. 通过读/写volatile字段来实现同步。见this SO帖子。这将确保安全,但会大大增加复杂性。在第二个想法,不要这样做:)

答案 2 :(得分:1)

您可以添加

  

同步

两种方法的关键字或使用

synchronized(Myclass.class) {
}

前者主要使用Myclass.class对象,但它不像后者那么精细。

答案 3 :(得分:1)

将两个方法声明为synchronized以锁定每个实例,或使用synchronized(this){...}块仅在当前实例上进行锁定。

答案 4 :(得分:1)

synchronized(myList) {
    // do stuff on myList
}

具体文件:Intrinsic Locks and Synchronization

然而,我鼓励您使用线程安全的并发数据结构来实现您想要实现的目标,以避免自己同步并获得(很多)更好的性能:Concurrent package summary