我有一个大问题。如何从同一个类同步两个不同的方法以锁定同一个对象?这是一个例子:
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
的类,并且只有该类的一个实例。在那个实例中,我创建n
个Thread
个实例,它们接受该列表的每个元素并用它做一些事情。
现在,在特定时刻,myList
已更新。那些已经在处理myList元素的线程会发生什么?在更新时如何锁定myList
上的访问权限?
答案 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)
你可以:
run
和doJob
synchronized
。这将使用this
作为锁; final
并在其上进行同步。这将使用list作为锁。将锁定字段声明为final
是一种很好的做法。这样,您的类的某些方法可以在一个对象上同步,而其他方法可以使用其他对象进行同步。这减少了锁争用,但增加了代码复杂性; java.util.concurrent.locks.Lock
变量并使用它的方法进行同步。这将提高代码灵活性,但也会增加代码复杂性; BlockingQueue
或CopyOnWriteArrayList
。这将降低代码复杂性并确保线程安全。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