From b9fc3a6d055cd06e5b40096c8712bc209d9a3681 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 20 Apr 2015 19:06:09 +0300 Subject: [PATCH] thread safety --- .../reference/RefEntityImpl.java | 68 +++++++++++++------ .../reference/RefManagerImpl.java | 25 ++++++- .../reference/RefModuleImpl.java | 55 +++++++++++---- 3 files changed, 109 insertions(+), 39 deletions(-) diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefEntityImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefEntityImpl.java index 8fb3d4e704c8..fc631f74c246 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefEntityImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefEntityImpl.java @@ -24,8 +24,8 @@ */ package com.intellij.codeInspection.reference; -import com.intellij.codeInspection.InspectionsBundle; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.util.BitUtil; import gnu.trove.THashMap; @@ -36,18 +36,17 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -public abstract class RefEntityImpl implements RefEntity { - private static final String NO_NAME = InspectionsBundle.message("inspection.reference.noname"); - private RefEntityImpl myOwner; - protected List myChildren; +abstract class RefEntityImpl implements RefEntity { + private RefEntityImpl myOwner; // guarded by myManager.myLock + protected List myChildren; // guarded by myManager.myLock private final String myName; private Map myUserMap; protected long myFlags; protected final RefManagerImpl myManager; - protected RefEntityImpl(String name, @NotNull RefManager manager) { + RefEntityImpl(@NotNull String name, @NotNull RefManager manager) { myManager = (RefManagerImpl)manager; - myName = name != null ? name : NO_NAME; + myName = name; myOwner = null; myChildren = null; } @@ -66,32 +65,57 @@ public abstract class RefEntityImpl implements RefEntity { @Override public List getChildren() { - return myChildren; + return myManager.doRead(new Computable>() { + @Override + public List compute() { + return myChildren; + } + }); } @Override public RefEntity getOwner() { - return myOwner; + return myManager.doRead(new Computable() { + @Override + public RefEntity compute() { + return myOwner; + } + }); } - protected void setOwner(RefEntityImpl owner) { - myOwner = owner; + protected void setOwner(final RefEntityImpl owner) { + myManager.doWrite(new Runnable() { + @Override + public void run() { + myOwner = owner; + } + }); } - public void add(RefEntity child) { - if (myChildren == null) { - myChildren = new ArrayList(1); - } + public void add(@NotNull final RefEntity child) { + myManager.doWrite(new Runnable() { + @Override + public void run() { + if (myChildren == null) { + myChildren = new ArrayList(1); + } - myChildren.add(child); - ((RefEntityImpl)child).setOwner(this); + myChildren.add(child); + ((RefEntityImpl)child).setOwner(RefEntityImpl.this); + } + }); } - protected void removeChild(RefEntity child) { - if (myChildren != null) { - myChildren.remove(child); - ((RefEntityImpl)child).setOwner(null); - } + protected void removeChild(@NotNull final RefEntity child) { + myManager.doWrite(new Runnable() { + @Override + public void run() { + if (myChildren != null) { + myChildren.remove(child); + ((RefEntityImpl)child).setOwner(null); + } + } + }); } public String toString() { diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java index 3188e593432a..d11b39cd7504 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java @@ -59,6 +59,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class RefManagerImpl extends RefManager { @@ -85,7 +86,7 @@ public class RefManagerImpl extends RefManager { private final Map myExtensions = new HashMap(); private final Map myLanguageExtensions = new HashMap(); - private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock(); + private final ReadWriteLock myLock = new ReentrantReadWriteLock(); public RefManagerImpl(@NotNull Project project, @Nullable AnalysisScope scope, @NotNull GlobalInspectionContext context) { myProject = project; @@ -533,9 +534,9 @@ public class RefManagerImpl extends RefManager { protected T getFromRefTableOrCache(final PsiElement element, @NotNull NullableFactory factory, @Nullable Consumer whenCached) { - T result; myLock.readLock().lock(); + T result; try { //noinspection unchecked result = (T)myRefTable.get(ApplicationManager.getApplication().runReadAction( @@ -624,6 +625,26 @@ public class RefManagerImpl extends RefManager { } } + public void doWrite(@NotNull Runnable runnable) { + myLock.writeLock().lock(); + try { + runnable.run(); + } + finally { + myLock.writeLock().unlock(); + } + } + + public T doRead(@NotNull Computable runnable) { + myLock.readLock().lock(); + try { + return runnable.compute(); + } + finally { + myLock.readLock().unlock(); + } + } + @Override public boolean belongsToScope(final PsiElement psiElement) { return belongsToScope(psiElement, false); diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefModuleImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefModuleImpl.java index 353052e9ccfc..10f0a501dfb3 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefModuleImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefModuleImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.codeInspection.reference; import com.intellij.openapi.application.ApplicationManager; @@ -14,32 +29,42 @@ import java.util.ArrayList; * User: anna * Date: 09-Jan-2006 */ -public class RefModuleImpl extends RefEntityImpl implements RefModule { +class RefModuleImpl extends RefEntityImpl implements RefModule { private final Module myModule; - protected RefModuleImpl(@NotNull Module module, @NotNull RefManager manager) { + RefModuleImpl(@NotNull Module module, @NotNull RefManager manager) { super(module.getName(), manager); myModule = module; ((RefProjectImpl)manager.getRefProject()).add(this); } @Override - public void add(RefEntity child) { - if (myChildren == null) { - myChildren = new ArrayList(); - } - myChildren.add(child); + public void add(@NotNull final RefEntity child) { + myManager.doWrite(new Runnable() { + @Override + public void run() { + if (myChildren == null) { + myChildren = new ArrayList(); + } + myChildren.add(child); - if (child.getOwner() == null) { - ((RefEntityImpl)child).setOwner(this); - } + if (child.getOwner() == null) { + ((RefEntityImpl)child).setOwner(RefModuleImpl.this); + } + } + }); } @Override - protected void removeChild(RefEntity child) { - if (myChildren != null) { - myChildren.remove(child); - } + protected void removeChild(@NotNull final RefEntity child) { + myManager.doWrite(new Runnable() { + @Override + public void run() { + if (myChildren != null) { + myChildren.remove(child); + } + } + }); } @Override @@ -69,7 +94,7 @@ public class RefModuleImpl extends RefEntityImpl implements RefModule { } @Nullable - public static RefEntity moduleFromName(final RefManager manager, final String name) { + static RefEntity moduleFromName(final RefManager manager, final String name) { return manager.getRefModule(ModuleManager.getInstance(manager.getProject()).findModuleByName(name)); } }