Java同步:同步方法和同步块
我有一个多线程Java应用程序。在一种方法中,需要同步ArrayList。因为arrayList不是线程安全的,所以我必须使用同步。问题是ArrayList类型的对象不是该对象的成员变量。该方法的原型如下:Java同步:同步方法和同步块,java,multithreading,Java,Multithreading,我有一个多线程Java应用程序。在一种方法中,需要同步ArrayList。因为arrayList不是线程安全的,所以我必须使用同步。问题是ArrayList类型的对象不是该对象的成员变量。该方法的原型如下: public void simultaneousAccess(ArrayListWrapper aListWrapper){ ArrayList list = aListWrapper.getList(); //...Codes manipulate the list
public void simultaneousAccess(ArrayListWrapper aListWrapper){
ArrayList list = aListWrapper.getList();
//...Codes manipulate the list
}
由于多线程,我应该使用
A
或
B
从性能测试来看,两者都不起作用。
但我不知道为什么
下面是完整的源代码:
package com.juhani.prototype.sync;
import java.util.ArrayList;
public class ArrayListWrapper {
public ArrayList<Integer> aList = new ArrayList<Integer>();
public ArrayListWrapper(){
Integer one = new Integer(1);
Integer two = new Integer(2);
Integer three = new Integer(3);
aList.add(one);
aList.add(two);
aList.add(three);
}
}
package com.juhani.prototype.sync;
import java.util.ArrayList;
public class TestClass {
public int count_test=0;
public synchronized void test(ArrayListWrapper listWrapper){
ArrayList<Integer> list = listWrapper.aList;
int temp = list.get(1)+1;
list.set(1,temp);
}
public void testBlock(ArrayListWrapper listWrapper){
ArrayList<Integer> list = listWrapper.aList;
synchronized(list){
int temp = list.get(1)+1;
list.set(1,temp);
}
}
}
package com.juhani.prototype.sync;
public class WorkerSyncObj extends Thread {
ArrayListWrapper listWrapper = null;
TestClass tc = null;
int number;
public WorkerSyncObj(int aNumber){
number = aNumber;
}
public void setListWrapper(ArrayListWrapper aListWrapper){
listWrapper = aListWrapper;
}
public void setTestClass(TestClass aTc){
tc = aTc;
}
public void run(){
int i = 1000;
for(int j=0;j<i;j++){
tc.testBlock(listWrapper);
System.out.println("Thread "+number+" is runing at loop "+j+" . index 1 value is:"+listWrapper.aList.get(1));
}
}
}
package com.juhani.prototype.sync.main;
import com.juhani.prototype.sync.ArrayListWrapper;
import com.juhani.prototype.sync.TestClass;
import com.juhani.prototype.sync.WorkerSyncObj;
public class TestMain {
public static void main(String[] args){
ArrayListWrapper list = new ArrayListWrapper();
TestClass tc = new TestClass();
WorkerSyncObj work1 = new WorkerSyncObj(1);
work1.setListWrapper(list);
work1.setTestClass(tc);
WorkerSyncObj work2 = new WorkerSyncObj(2);
work2.setListWrapper(list);
work2.setTestClass(tc);
WorkerSyncObj work3 = new WorkerSyncObj(3);
work3.setListWrapper(list);
work3.setTestClass(tc);
work1.start();
work2.start();
work3.start();
}
}
在第一种情况下,锁定this对象,而在第二种情况下锁定list对象。如果从不同的对象调用该方法,但列表相同,则可能会出现问题。这可能是第一种情况下出现异常的原因。
或者,您可以尝试一些内置的并发类型,如Collections.synchronizedList或CopyOnWriteArrayList。在第一种情况下,您锁定此对象,而在第二种情况下锁定列表对象。如果从不同的对象调用该方法,但列表相同,则可能会出现问题。这可能是第一种情况下出现异常的原因。
或者,您可以尝试一些内置的并发类型,如Collections.synchronizedList或CopyOnWriteArrayList。在java中,每个对象实例都有一个内部锁以及相应的类本身。同步密钥工作实际上是使用内部锁进行独占访问,即
syncrhonized method(...) {...}
等于
method(...) {
this.intrinsicLock.lock();
...;
this.intrinsicLock.unlock() }
及
等于
obj_ref.intrinsicLock.lock();
{...}
obj_ref.instrinsicLock.unlock();
因此,同步化的方法不适合保护列表参数。如果使用同步列表,则会出现两个问题:
1.独占访问的粒度似乎有点粗糙
2.整个程序中的每个列表访问都需要使用同步列表。这是专用访问的协议
这就是Java库提供相当多并发数据结构的原因。在Java中,每个对象实例都有一个内在的锁以及相应的类本身。同步密钥工作实际上是使用内部锁进行独占访问,即
syncrhonized method(...) {...}
等于
method(...) {
this.intrinsicLock.lock();
...;
this.intrinsicLock.unlock() }
及
等于
obj_ref.intrinsicLock.lock();
{...}
obj_ref.instrinsicLock.unlock();
因此,同步化的方法不适合保护列表参数。如果使用同步列表,则会出现两个问题:
1.独占访问的粒度似乎有点粗糙
2.整个程序中的每个列表访问都需要使用同步列表。这是专用访问的协议
这就是Java库提供相当多并发数据结构的原因。使用Collections.synchronizatedList和CopyOnWriteArrayList是非常好的建议。我也会试试这个。我必须纠正我的结果。我尝试了同步块和同步方法。两者都不起作用。现在我来试试泽勒的建议。我在问题中添加了我的源代码。我当时不知道。您能识别引发异常的行吗?我看不到列表中有更多的并发写入,只有当log.WorkerSyncObj.run调用具有arraylist.set方法的tc.testBlock时,run方法中有一个并发读取。这是列表的并发写入吗?并发,但已同步,因为testBlock使读写操作原子化,在给定时间只有一个线程修改列表,其他线程在外部等待。使用Collections.synchronizatedList和CopyOnWriteArrayList是非常好的建议。我也会试试这个。我必须纠正我的结果。我尝试了同步块和同步方法。两者都不起作用。现在我来试试泽勒的建议。我在问题中添加了我的源代码。我当时不知道。您能识别引发异常的行吗?我看不到列表中有更多的并发写入,只有当log.WorkerSyncObj.run调用具有arraylist.set方法的tc.testBlock时,run方法中有一个并发读取。这是列表的并发写入吗?并发但同步,因为testBlock使读写操作原子化,在给定时间只有一个线程修改列表,其他线程在外面等待。