2012-03-12 161 views
0

我需要一些帮助,以确保我理解同步块。假设下面的例子:Java线程:同步块

public class ThreadStarter { 
    public static void main(String[] args) { 

     Queue queueObject = new Queue(); 

     ThreadA thread1 = new ThreadA(queueObject); 
     ThreadA thread2 = new ThreadA(queueObject); 

     ThreadB thread3 = new ThreadB(queueObject); 
     ThreadB thread4 = new ThreadB(queueObject); 

     thread1.start(); 
     thread2.start(); 

    } 
} 

public class Queue { 

    Object[] the theQueue; 

    public Queue(int size){ 
     theQueue = new Object[size]; 
    } 

    public submitObject(Object o){ 
     /* add Object to the queue */ 
    } 

    public deleteObject(int objectId){ 
     /*delete Object from the queue */ 
    } 
} 

public class ThreadA extends Thread { 

    private Queue queue; 

    public ThreadA(Queue queue){ 
     this.queue = queue; 
    } 

    public void run() { 
     while(!isInterrupted()){ 
      synchronized(queue) { 
       Object o = new Object 
       queue.submitObject(o); 
       /* do some other stuff */ 
     } 

     try { 
      sleep((int)(Math.random()*1000)); 
     } catch (interruptedException) { 
      Thread.currentThread().interrupt; 
     } 

      synchronized(queue) { 
       /* do some other stuff on the queue */ 
      } 
     } 
    } 
} 

public class ThreadB extends Thread { 

    private Queue queue; 

    public ThreadB(Queue queue){ 
     this.queue = queue; 
    } 

    public void run() { 
     while(!isInterrupted()){ 
      synchronized(queue) { 
       queue.deleteObject(o); 
       /* do some other stuff */ 
     } 

     try { 
      sleep(1000); 
     } catch (interruptedException) { 
      Thread.currentThread().interrupt; 
     } 
    } 
} 
} 

我的问题是,它足以同步ThreadA中的整个队列对象提交的目标队列类,是在安全方面?我在ThreadB中做了同样的操作,从队列中删除一个对象。或者,我还必须同步Queue类中的submitObject()和deleteObject()方法吗?

在我的理解中,如果我像上面显示的那样锁定了线程中的整个队列类,我应该保持安全 - 对吧?

greetZ并提前致谢。

回答

2

所有你需要做的是确保没有两个线程不能同时进入submitObject & deleteObjecct。要做到这一点,只需声明这些方法是同步的。 在这种情况下,类之间共享的队列对象将阻止2个线程在同步的块上进行。

如果你愿意,而且有某种闭锁机制,如:

“如果一个线程想删除一个对象,它必须等待,如果有 没有这样的一个对象队列。”

,那么你需要做的不仅仅是同步这种方式更多:这两种方法应该还是同步的,但进入DeleteObject的线程应该使用this.wait由队列停止,直到有一个对象变为可用:

public synchronized deleteObject() { 
    while(isEmpty()) { 
    try { 
     wait(); 
    } catch(Exception ex) { 
     ex.printStackTrace(); 
    }//catch 
    }//while 

    //actually do delete object. 
    ... 
}//met 

然后submitObject应该做通知等待状态线程:

public synchronized submitObject() { 
    //do put object 
    ... 
    notifyAll(); 
}//met 

,你也可以穿越的角色和在两种方法中添加一些代码,在立场,允许提交者在队列已满时被阻止,并在队列中剩余一些空间时通知。

1

我会在submitObjectdeleteObject方法队列对象上同步,这应该是足够的,这意味着:

public submitObject(Object o){ 
    synchronized (theQueue) { 
     ... 
    } 
} 

public deleteObject(int objectId){ 
    synchronized (theQueue) { 
     ... 
    } 
} 
1

你要做的就是相当于同步方法(public synchronized method()this同步这是您的queue局部变量),只是必须记住每次使用队列时都需要执行此操作。同步提交和删除方法会更安全.... 它也会从同步块中删除Object o = new Object()

+0

+1:你封装同步的越多,它越容易和安全。 – 2012-03-12 19:43:39

+1

它在功能上并不等同于“队列”的方法。如果他这样做了,那么在每个'synchronized'部分找到的'/ *'还有一些其他的东西* /'不会处于关键部分并且可以并行运行。根据代码的内容,这对同步也很重要。这与同步列表很相似:如果你想以原子方式执行多个操作(例如遍历它),你仍然需要在列表上进行外部同步。 – 2012-03-12 20:00:58

+0

@MaxPeters完全同意。 – assylias 2012-03-12 20:02:12