thread safety

This commit is contained in:
Alexey Kudravtsev
2015-04-21 14:25:33 +03:00
parent 1d96ffead0
commit b9fc3a6d05
3 changed files with 109 additions and 39 deletions
@@ -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<RefEntity> myChildren;
abstract class RefEntityImpl implements RefEntity {
private RefEntityImpl myOwner; // guarded by myManager.myLock
protected List<RefEntity> myChildren; // guarded by myManager.myLock
private final String myName;
private Map<Key, Object> 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<RefEntity> getChildren() {
return myChildren;
return myManager.doRead(new Computable<List<RefEntity>>() {
@Override
public List<RefEntity> compute() {
return myChildren;
}
});
}
@Override
public RefEntity getOwner() {
return myOwner;
return myManager.doRead(new Computable<RefEntity>() {
@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<RefEntity>(1);
}
public void add(@NotNull final RefEntity child) {
myManager.doWrite(new Runnable() {
@Override
public void run() {
if (myChildren == null) {
myChildren = new ArrayList<RefEntity>(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() {
@@ -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<Key, RefManagerExtension> myExtensions = new HashMap<Key, RefManagerExtension>();
private final Map<Language, RefManagerExtension> myLanguageExtensions = new HashMap<Language, RefManagerExtension>();
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 extends RefElement> T getFromRefTableOrCache(final PsiElement element,
@NotNull NullableFactory<T> factory,
@Nullable Consumer<T> 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> T doRead(@NotNull Computable<T> runnable) {
myLock.readLock().lock();
try {
return runnable.compute();
}
finally {
myLock.readLock().unlock();
}
}
@Override
public boolean belongsToScope(final PsiElement psiElement) {
return belongsToScope(psiElement, false);
@@ -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<RefEntity>();
}
myChildren.add(child);
public void add(@NotNull final RefEntity child) {
myManager.doWrite(new Runnable() {
@Override
public void run() {
if (myChildren == null) {
myChildren = new ArrayList<RefEntity>();
}
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));
}
}