以下代码(显示部分)创建类DescCalculator的对象并计算描述符并将它们作为字符串数组返回。传递分子和Descriptor对象的ArrayList。
private void calcDesc()
{
try
{
StatusPanel.setStatus("Calculating Molecular Descriptors Using CDK...\n");
File df = new File(Settings.getCurrentDirectory() + sep + "molDesc.csv");
FileWriter dfw = new FileWriter(df);
LoadSDF lsdf1 = new LoadSDF(Settings.getCurrentDirectory() + sep + "marvin3D.sdf");
List<IAtomContainer> mols3D = lsdf1.getCompounds();
DescriptorEngine engine = new DescriptorEngine(DescriptorEngine.MOLECULAR);
List<String> classNames = engine.getDescriptorClassNames();
List<String> removeList = new ArrayList();
removeList.add("org.openscience.cdk.qsar.descriptors.molecular.IPMolecularLearningDescriptor");
classNames.removeAll(removeList);
List<IDescriptor> instances = engine.instantiateDescriptors(classNames);
engine.setDescriptorInstances(instances);
List<String> headerItems = new ArrayList<String>();
headerItems.add("CID");
headerItems.add("MobCSA");
for (IDescriptor descriptor : instances) {
String[] names = descriptor.getDescriptorNames();
headerItems.addAll(Arrays.asList(names));
}
ArrayList<IMolecularDescriptor> descriptors = new ArrayList();
for (Object object : instances)
{
IMolecularDescriptor descriptor = (IMolecularDescriptor) object;
String[] comps = descriptor.getSpecification().getSpecificationReference().split("#");
descriptors.add(descriptor);
}
String headerLine = "";
for (String header : headerItems) {
headerLine = headerLine + header + ",";
}
dfw.append(headerLine+"\n");
ExecutorService eservice = Executors.newFixedThreadPool(threads);
CompletionService <List<String>> cservice = new ExecutorCompletionService <List<String>> (eservice);
int k=0;
for (IAtomContainer mol : mols3D)
{
DescCalculator dc = new DescCalculator(mol,descriptors);
cservice.submit(dc);
k=k+1;
}
for (int j=1 ; j<=k; j++)
{
StatusPanel.setStatus("Calculating Descriptors for Molecule "+j+"/"+compounds.size()+" Using "+threads+" Processors\n");
List<String> dataItems = cservice.take().get();
for (int i = 0; i < dataItems.size(); i++) {
if (dataItems.get(i).equals("NaN")) {
dataItems.set(i, "NA");
}
}
try {
String dataLine = "";
for (String data : dataItems) {
dataLine = dataLine + data + ",";
}
dfw.append(dataLine+"\n");
} catch (Exception e) {
System.out.println(e.toString());
}
}
dfw.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
在类中,有一个for循环遍历描述符列表,如下所示(部分显示)。此代码运行到并发修改异常。如果我在synchronized {}块中使用threads = 1或者描述符迭代,那么代码运行正常,但是我没有得到所需的并行化。如何遍历类DesCalculator内的列表?
public class DescCalculator implements Callable<List<String>>{
private IAtomContainer mol = new Molecule();
private ArrayList<IMolecularDescriptor> molDesc;
DescCalculator(IAtomContainer mol_, ArrayList<IMolecularDescriptor> molDesc_)
{
this.mol = mol_;
this.molDesc = molDesc_;
}
@Override
public List<String> call() {
List<String> dataItems = new ArrayList<String>();
try
{
String title = (String) mol.getProperty("PUBCHEM_COMPOUND_CID");
dataItems.add(title);
//String csa = Double.toString(mobcalCSA.get(ind));
String csa = "NA";
dataItems.add(csa);
int ndesc = 0;
for (IMolecularDescriptor descriptor : molDesc) {
descriptor.calculate(mol);
DescriptorValue value = descriptor.calculate(mol);
if (value.getException() != null) {
for (int i = 0; i < value.getNames().length; i++) {
dataItems.add("NA");
}
continue;
}
IDescriptorResult result = value.getValue();
if (result instanceof DoubleResult) {
dataItems.add(String.valueOf(((DoubleResult) result).doubleValue()));
} else if (result instanceof IntegerResult) {
dataItems.add(String.valueOf(((IntegerResult) result).intValue()));
} else if (result instanceof DoubleArrayResult) {
for (int i = 0; i < ((DoubleArrayResult) result).length(); i++) {
dataItems.add(String.valueOf(((DoubleArrayResult) result).get(i)));
}
} else if (result instanceof IntegerArrayResult) {
for (int i = 0; i < ((IntegerArrayResult) result).length(); i++) {
dataItems.add(String.valueOf(((IntegerArrayResult) result).get(i)));
}
}
ndesc++;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return dataItems;
}
}
打印堆栈跟踪
java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at org.openscience.cdk.ChemObject.notifyChanged(ChemObject.java:187)
at org.openscience.cdk.ChemObject.setFlag(ChemObject.java:375)
at org.openscience.cdk.graph.PathTools.depthFirstTargetSearch(PathTools.java:168)
at org.openscience.cdk.graph.PathTools.depthFirstTargetSearch(PathTools.java:177)
at org.openscience.cdk.graph.PathTools.depthFirstTargetSearch(PathTools.java:177)
at org.openscience.cdk.graph.SpanningTree.getRing(SpanningTree.java:185)
at org.openscience.cdk.graph.SpanningTree.getCyclicFragmentsContainer(SpanningTree.java:221)
at org.openscience.cdk.atomtype.CDKAtomTypeMatcher.getRing(CDKAtomTypeMatcher.java:912)
at org.openscience.cdk.atomtype.CDKAtomTypeMatcher.perceiveNitrogens(CDKAtomTypeMatcher.java:730)
at org.openscience.cdk.atomtype.CDKAtomTypeMatcher.findMatchingAtomType(CDKAtomTypeMatcher.java:117)
at org.openscience.cdk.tools.manipulator.AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(AtomContainerManipulator.java:719)
at org.openscience.cdk.smiles.smarts.SMARTSQueryTool.initializeMolecule(SMARTSQueryTool.java:435)
at org.openscience.cdk.smiles.smarts.SMARTSQueryTool.matches(SMARTSQueryTool.java:214)
at org.openscience.cdk.smiles.smarts.SMARTSQueryTool.matches(SMARTSQueryTool.java:189)
at org.openscience.cdk.qsar.descriptors.molecular.AcidicGroupCountDescriptor.calculate(AcidicGroupCountDescriptor.java:135)
at edu.uconn.pharmacy.molfind.DescCalculator.call(DescCalculator.java:48)
at edu.uconn.pharmacy.molfind.DescCalculator.call(DescCalculator.java:25)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
答案 0 :(得分:1)
除非您实际上修改 Collection
,否则不应该获得异常。通常,这可以通过从您正在迭代的Collection
中删除来在1个主题中完成 - 例如在for
中。
但是在你的情况下,我猜你正在某处删除molDesc
列表,尽管我在你提供的代码示例中看不到。如果需要从列表中删除条目,则必须使用其他一些机制来执行删除操作。您不能在多个线程中更改同一个集合,除非它以某种方式synchronized
。
结合其他想法:
现在确定它是否需要完全相同的列表。您可以让每个线程使用列表的副本。
DescCalculator dc =
new DescCalculator(mol, new ArrayList<IMolecularDescriptor>(descriptors));
您可以直接传递Collections.synchronizedList
molDesc
的{{1}}副本,但我不确定这是您想要的。
List<IMolecularDescriptor> syncedList =
Collections.synchronizedList(descriptors);
...
DescCalculator dc = new DescCalculator(mol, syncedList);
每个帖子都可以保留需要删除的项目列表。最后,您可以在获取线程时使用Future
获取已删除的项目列表,并在结尾处将其从列表中删除。
答案 1 :(得分:0)
您的molDesc字段是访问call()方法的2个或更多线程之间的共享状态。正如您所说,避免CME的唯一方法是将迭代包装在synchronized()块中(这将阻止您进行并行化),或者像Victor提到的那样使用像CopyOnWriteArrayList这样的线程安全结构。
答案 2 :(得分:0)
事实证明,问题在于描述符对象不是线程安全的。我感谢Affe指出来了!在DescCalculator类中生成它们可以解决问题。我感谢大家的投入!