一种方法是使用锁(查看java.util.concurrent.locks 包),但我首先会考虑是否可以改进一般方法,例如使用无锁算法等。
另一种方法是在共享对象上使用synchronized 方法/块。然而,这一切都取决于你实际想要达到的目标。
使用synchronized 块的示例:
T1:
while(...) {
synchronized( SomeClass.class ) {
doWork();
}
}
T2:
while(...) {
doWork();
synchronized( SomeClass.class ) {
update();
}
}
在这里,您将在 Class<SomeClass> 的同一实例上进行同步,只要您使用相同的类加载器,它就可以工作。
请记住,您应该使同步块尽可能小,以免添加不必要的阻塞。
除此之外,请注意 T1 中的同步块可能会使 T2 难以在两次迭代之间中断。然而,问题是为什么它是这样设计的。
编辑
作为同步整个 doWork() 调用的替代方法,您可能需要考虑实际需要同步的内容。
以如下伪代码为例:
WorkResult doWork(SharedObject so) {
Data data = so.loadData();
WorkResult wr = doSomeLengthyWork(data);
return wr;
}
void update(WorkResult wr, SharedObject so) {
so.updateFromWorkResult( wr );
}
如果你的情况是这样的,你可以同步调用so.loadData()和so.updateFromWorkResult(),让冗长的操作在so.loadData()提供的数据副本上工作。
编辑 2:
您也可以使用ReadWriteLock 实现:
T1:
while(...) {
Lock readlock = readWriteLock.readLock();
readlock.lock();
doWork();
readlock.unlock();
}
T2:
while(...) {
doWork();
Lock writelock= readWriteLock.writeLock();
writelock.lock();
update();
writelock.unlock();
}
请注意,为简单起见,我省略了异常处理等。
您在这里所做的基本上是在工作期间获取读锁,在更新时获取写锁。除非有写锁(允许多个读锁),否则多个线程可以并行工作,并且更新将等到所有读锁都被释放。为了实现这一点,您可以在公平模式下使用ReentrantReadWriteLock,它应该按照请求的顺序发出锁,即当 T2 请求锁而 T1 仍在读取时,它将获得下一个锁,尽管 T1 立即请求再次锁定。