reduce contention

This commit is contained in:
Alexey Kudravtsev
2014-06-16 15:46:17 +04:00
parent b3073faf17
commit 4021a73190
@@ -19,6 +19,7 @@ import com.intellij.BundleBase;
import com.intellij.CommonBundle;
import com.intellij.diagnostic.PerformanceWatcher;
import com.intellij.diagnostic.PluginException;
import com.intellij.diagnostic.ThreadDumper;
import com.intellij.ide.*;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
@@ -80,7 +81,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"})
public class ApplicationImpl extends PlatformComponentManagerImpl implements ApplicationEx {
private static final Logger LOG = Logger.getInstance("#com.intellij.application.impl.ApplicationImpl");
private final ModalityState MODALITY_STATE_NONE = ModalityState.NON_MODAL;
@@ -96,7 +96,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
private IApplicationStore myComponentStore;
private boolean myTestModeFlag;
private final boolean myTestModeFlag;
private final boolean myHeadlessMode;
private final boolean myCommandLineMode;
@@ -107,12 +107,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
private volatile Runnable myExceptionalThreadWithReadAccessRunnable;
private int myInEditorPaintCounter = 0;
private long myStartTime = 0;
private int myInEditorPaintCounter; // EDT only
private final long myStartTime;
@Nullable
private final Splash mySplash;
private boolean myDoNotSave;
private volatile boolean myDisposeInProgress = false;
private volatile boolean myDisposeInProgress;
private final Disposable myLastDisposable = Disposer.newDisposable(); // will be disposed last
@@ -171,7 +171,30 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
private Boolean myActive;
private static final ThreadLocal<Integer> ourEdtSafe = new ThreadLocal<Integer>();
private static final int IS_EDT_FLAG = 1<<30; // we don't mess with sign bit since we want to do arithmetic
private static final int IS_READ_LOCK_ACQUIRED_FLAG = 1<<29;
private static final int IS_EXCEPTIONAL_THREAD_FLAG = 1<<28;
private static class Status {
// higher three bits are for IS_* flags
// lower bits are for edtSafe counter
private int flags;
}
private static final ThreadLocal<Status> status = new ThreadLocal<Status>(){
@Override
protected Status initialValue() {
Status status = new Status();
status.flags = BitUtil.set(status.flags, IS_EDT_FLAG, EventQueue.isDispatchThread());
return status;
}
};
private static Status getStatus() {
return status.get();
}
private static void setReadLockAcquired(Status status, boolean acquired) {
status.flags = BitUtil.set(status.flags, IS_READ_LOCK_ACQUIRED_FLAG, acquired);
}
@NonNls private static final ModalityState ANY = new ModalityState() {
@Override
public boolean dominates(@NotNull ModalityState anotherState) {
@@ -201,7 +224,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
}
@Override
public void initializeComponent(Object component, boolean service) {
public void initializeComponent(@NotNull Object component, boolean service) {
getStateStore().initComponent(component, service);
}
@@ -233,7 +256,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
myHeadlessMode = isHeadless;
myCommandLineMode = isCommandLine;
myDoNotSave = myTestModeFlag || myHeadlessMode;
myDoNotSave = isUnitTestMode || isHeadless;
loadApplicationComponents();
@@ -353,7 +376,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public boolean holdsReadLock() {
return myLock.getReadHoldCount() != 0;
return holdsReadLock(getStatus());
}
private static boolean holdsReadLock(Status status) {
return BitUtil.isSet(status.flags, IS_READ_LOCK_ACQUIRED_FLAG);
}
private void loadApplicationComponents() {
@@ -367,7 +394,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
}
@Override
protected synchronized Object createComponent(Class componentInterface) {
protected synchronized Object createComponent(@NotNull Class componentInterface) {
Object component = super.createComponent(componentInterface);
if (mySplash != null) {
mySplash.showProgress("", 0.65f + getPercentageOfComponentsLoaded() * 0.35f);
@@ -375,6 +402,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return component;
}
@NotNull
@Override
protected MutablePicoContainer createPicoContainer() {
return Extensions.getRootArea().getPicoContainer();
@@ -395,10 +423,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return myTestModeFlag;
}
public void setUnitTestMode(boolean testModeFlag) {
myTestModeFlag = testModeFlag;
}
@Override
public boolean isHeadlessEnvironment() {
return myHeadlessMode;
@@ -415,6 +439,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return ourThreadExecutorsService.submit(new Runnable() {
@Override
public void run() {
if (isReadAccessAllowed()) {
assert false : describe(Thread.currentThread());
}
try {
action.run();
}
@@ -427,6 +454,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
finally {
//ReflectionUtil.resetThreadLocals();
Thread.interrupted(); // reset interrupted status
if (isReadAccessAllowed()) {
assert false : describe(Thread.currentThread());
}
}
}
});
@@ -438,6 +468,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return ourThreadExecutorsService.submit(new Callable<T>() {
@Override
public T call() {
if (isReadAccessAllowed()) {
assert false : describe(Thread.currentThread());
}
try {
return action.call();
}
@@ -450,17 +483,22 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
finally {
//ReflectionUtil.resetThreadLocals();
Thread.interrupted(); // reset interrupted status
if (isReadAccessAllowed()) {
assert false : describe(Thread.currentThread());
}
}
return null;
}
});
}
private static Thread ourDispatchThread = null;
@Override
public boolean isDispatchThread() {
return EventQueue.isDispatchThread();
return isDispatchThread(getStatus());
}
private static boolean isDispatchThread(Status status) {
return BitUtil.isSet(status.flags, IS_EDT_FLAG);
}
@Override
@@ -535,7 +573,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
}
@Override
protected <T> T getComponentFromContainer(final Class<T> interfaceClass) {
protected <T> T getComponentFromContainer(@NotNull final Class<T> interfaceClass) {
if (myIsFiringLoadingEvent) {
return null;
}
@@ -567,13 +605,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
Disposer.dispose(myLastDisposable); // dispose it last
}
private final Object lock = new Object();
private void makeChangesVisibleToEDT() {
synchronized (lock) {
lock.hashCode();
}
}
@Override
public boolean runProcessWithProgressSynchronously(@NotNull final Runnable process,
@NotNull String progressTitle,
@@ -629,7 +660,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public void run() {
if (myExceptionalThreadWithReadAccessRunnable != process) {
LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable);
LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable);
}
executeOnPooledThread(new Runnable() {
@@ -639,9 +670,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable);
}
final boolean old = setExceptionalThreadWithReadAccessFlag(true);
LOG.assertTrue(isReadAccessAllowed());
setExceptionalThreadWithReadAccessFlag(true);
try {
LOG.assertTrue(isReadAccessAllowed());
ProgressManager.getInstance().runProcess(process, progress);
}
catch (ProcessCanceledException e) {
@@ -653,8 +684,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
throw e;
}
finally {
setExceptionalThreadWithReadAccessFlag(old);
makeChangesVisibleToEDT();
setExceptionalThreadWithReadAccessFlag(false);
}
}
});
@@ -669,7 +699,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
}
finally {
myExceptionalThreadWithReadAccessRunnable = null;
makeChangesVisibleToEDT();
}
return !progress.isCanceled();
@@ -677,12 +706,13 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public void invokeAndWait(@NotNull Runnable runnable, @NotNull ModalityState modalityState) {
if (isDispatchThread()) {
Status status = getStatus();
if (isDispatchThread(status)) {
runnable.run();
return;
}
if (!isExceptionalThreadWithReadAccess() && holdsReadLock()) {
if (!isExceptionalThreadWithReadAccess(status) && holdsReadLock(status)) {
LOG.error("Calling invokeAndWait from read-action leads to possible deadlock.");
}
@@ -712,13 +742,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
@NotNull
public ModalityState getDefaultModalityState() {
if (EventQueue.isDispatchThread()) {
if (isDispatchThread()) {
return getCurrentModalityState();
}
else {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
return progress == null ? getNoneModalityState() : progress.getModalityState();
}
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
return progress == null ? getNoneModalityState() : progress.getModalityState();
}
@Override
@@ -769,7 +797,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
private static volatile boolean exiting = false;
public void exit(final boolean force, final boolean allowListenersToCancel, final boolean restart) {
if (exiting) return;
exiting = true;
@@ -788,19 +815,19 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).appClosing();
myDisposeInProgress = true;
if (!doExit(allowListenersToCancel, restart)) {
myDisposeInProgress = false;
}
doExit(allowListenersToCancel, restart);
myDisposeInProgress = false;
}
};
if (!isDispatchThread()) {
invokeLater(runnable, ModalityState.NON_MODAL);
}
else {
if (isDispatchThread()) {
runnable.run();
}
} finally {
else {
invokeLater(runnable, ModalityState.NON_MODAL);
}
}
finally {
exiting = false;
}
}
@@ -857,6 +884,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return false;
}
@NotNull
@Override
public String getDoNotShowMessage() {
return "Do not ask me again";
@@ -896,13 +924,15 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public void runReadAction(@NotNull final Runnable action) {
if (isReadAccessAllowed()) {
Status status = getStatus();
if (isReadAccessAllowed(status)) {
action.run();
}
else {
assertReadActionAllowed();
assertNoPsiLock();
try {
myLock.readLock().lockInterruptibly();
setReadLockAcquired(status, true);
}
catch (InterruptedException e) {
throw new RuntimeInterruptedException(e);
@@ -911,70 +941,66 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
action.run();
}
finally {
setReadLockAcquired(status, false);
myLock.readLock().unlock();
}
}
}
@Override
public <T> T runReadAction(@NotNull final Computable<T> computation) {
if (isReadAccessAllowed()) {
Status status = getStatus();
if (isReadAccessAllowed(status)) {
return computation.compute();
}
else {
assertReadActionAllowed();
try {
myLock.readLock().lockInterruptibly();
}
catch (InterruptedException e) {
throw new RuntimeInterruptedException(e);
}
try {
return computation.compute();
}
finally {
myLock.readLock().unlock();
}
assertNoPsiLock();
try {
myLock.readLock().lockInterruptibly();
setReadLockAcquired(status, true);
}
catch (InterruptedException e) {
throw new RuntimeInterruptedException(e);
}
try {
return computation.compute();
}
finally {
setReadLockAcquired(status, false);
myLock.readLock().unlock();
}
}
@Override
public <T, E extends Throwable> T runReadAction(@NotNull ThrowableComputable<T, E> computation) throws E {
if (isReadAccessAllowed()) {
Status status = getStatus();
if (isReadAccessAllowed(status)) {
return computation.compute();
}
else {
assertReadActionAllowed();
try {
myLock.readLock().lockInterruptibly();
}
catch (InterruptedException e) {
throw new RuntimeInterruptedException(e);
}
try {
return computation.compute();
}
finally {
myLock.readLock().unlock();
}
assertNoPsiLock();
try {
myLock.readLock().lockInterruptibly();
setReadLockAcquired(status, true);
}
catch (InterruptedException e) {
throw new RuntimeInterruptedException(e);
}
try {
return computation.compute();
}
finally {
setReadLockAcquired(status, false);
myLock.readLock().unlock();
}
}
private static final ThreadLocal<Boolean> exceptionalThreadWithReadAccessFlag = new ThreadLocal<Boolean>();
private static boolean isExceptionalThreadWithReadAccess() {
Boolean flag = exceptionalThreadWithReadAccessFlag.get();
return flag == Boolean.TRUE;
private static boolean isExceptionalThreadWithReadAccess(Status status) {
return BitUtil.isSet(status.flags, IS_EXCEPTIONAL_THREAD_FLAG);
}
public static boolean setExceptionalThreadWithReadAccessFlag(boolean flag) {
boolean old = isExceptionalThreadWithReadAccess();
if (flag) {
exceptionalThreadWithReadAccessFlag.set(Boolean.TRUE);
}
else {
exceptionalThreadWithReadAccessFlag.remove();
}
return old;
public static void setExceptionalThreadWithReadAccessFlag(boolean flag) {
Status status = getStatus();
assert !isDispatchThread(status) : "exceptional thread must not be EDT";
assert flag != isReadAccessAllowed(status) : "must not start exceptional thread from inside read action";
status.flags = BitUtil.set(status.flags, IS_EXCEPTIONAL_THREAD_FLAG, flag);
}
@Override
@@ -1012,7 +1038,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public boolean hasWriteAction(@Nullable Class<?> actionClass) {
assertCanRunWriteAction();
assertCanRunWriteAction(getStatus());
for (int i = myWriteActionsStack.size() - 1; i >= 0; i--) {
Class action = myWriteActionsStack.get(i);
@@ -1028,7 +1054,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
LOG.error(
"Read access is allowed from event dispatch thread or inside read-action only" +
" (see com.intellij.openapi.application.Application.runReadAction())",
"Current thread: " + describe(Thread.currentThread()), "Our dispatch thread:" + describe(ourDispatchThread),
"Current thread: " + describe(Thread.currentThread()), "; dispatch thread: " + EventQueue.isDispatchThread() +"; isDispatchThread(): "+isDispatchThread(),
"SystemEventQueueThread: " + describe(getEventQueueThread()));
}
}
@@ -1039,7 +1065,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return o + " " + System.identityHashCode(o);
}
@Nullable
private static Thread getEventQueueThread() {
EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
try {
@@ -1047,63 +1072,63 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
method.setAccessible(true);
return (Thread)method.invoke(eventQueue);
}
catch (Exception e1) {
// ok
catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
@Override
public boolean isReadAccessAllowed() {
Thread currentThread = Thread.currentThread();
return ourDispatchThread == currentThread ||
isExceptionalThreadWithReadAccess() ||
holdsReadLock() ||
isDispatchThread();
return isReadAccessAllowed(getStatus());
}
private static void assertCanRunWriteAction() {
assertIsDispatchThread("Write access is allowed from event dispatch thread only");
private static boolean isReadAccessAllowed(Status status) {
return (status.flags & (IS_EDT_FLAG | IS_EXCEPTIONAL_THREAD_FLAG | IS_READ_LOCK_ACQUIRED_FLAG)) != 0;
}
private static void assertCanRunWriteAction(Status status) {
assertIsDispatchThread(status, "Write access is allowed from event dispatch thread only");
}
@Override
public void assertIsDispatchThread() {
if (ShutDownTracker.isShutdownHookRunning()) return;
Integer safeCounter = ourEdtSafe.get();
if (safeCounter != null && safeCounter > 0) return;
assertIsDispatchThread("Access is allowed from event dispatch thread only.");
assertIsDispatchThread(getStatus());
}
private static void assertIsDispatchThread(@NotNull String message) {
final Thread currentThread = Thread.currentThread();
if (ourDispatchThread == currentThread) return;
if (EventQueue.isDispatchThread()) {
ourDispatchThread = currentThread;
private static void assertIsDispatchThread(Status status) {
if (isDispatchThread(status)) return;
if (ShutDownTracker.isShutdownHookRunning()) return;
int safeCounter = getSafeCounter(status);
if (safeCounter == 0) {
assertIsDispatchThread(status, "Access is allowed from event dispatch thread only.");
}
if (ourDispatchThread == currentThread) return;
}
private static int getSafeCounter(Status status) {
return status.flags & 0x1fffffff;
}
private static void assertIsDispatchThread(Status status, @NotNull String message) {
if (isDispatchThread(status)) return;
LOG.error(message,
"EventQueue.isDispatchThread()="+EventQueue.isDispatchThread(),
"isDispatchThread()="+isDispatchThread(getStatus()),
"Toolkit.getEventQueue()="+Toolkit.getDefaultToolkit().getSystemEventQueue(),
"Current thread: " + describe(Thread.currentThread()),
"Our dispatch thread:" + describe(ourDispatchThread),
"SystemEventQueueThread: " + describe(getEventQueueThread()));
"SystemEventQueueThread: " + describe(getEventQueueThread()) +"\n"+ ThreadDumper.dumpThreadsToString()+"\n-----------");
}
@Override
public void runEdtSafeAction(@NotNull Runnable runnable) {
Integer value = ourEdtSafe.get();
if (value == null) {
value = 0;
}
ourEdtSafe.set(value + 1);
Status status = getStatus();
LOG.assertTrue(getSafeCounter(status) < 1<<26);
status.flags++;
try {
runnable.run();
}
finally {
int newValue = ourEdtSafe.get() - 1;
ourEdtSafe.set(newValue >= 1 ? newValue : null);
status.flags--;
}
}
@@ -1111,19 +1136,19 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
public void assertIsDispatchThread(@Nullable final JComponent component) {
if (component == null) return;
Thread curThread = Thread.currentThread();
if (ourDispatchThread == curThread) {
Status status = getStatus();
if (isDispatchThread(status)) {
return;
}
if (Boolean.TRUE.equals(component.getClientProperty(WAS_EVER_SHOWN))) {
assertIsDispatchThread();
assertIsDispatchThread(status);
}
else {
final JRootPane root = component.getRootPane();
if (root != null) {
component.putClientProperty(WAS_EVER_SHOWN, Boolean.TRUE);
assertIsDispatchThread();
assertIsDispatchThread(status);
}
}
}
@@ -1136,14 +1161,16 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public boolean tryRunReadAction(@NotNull Runnable action) {
//if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction
boolean mustAcquire = !isReadAccessAllowed();
Status status = getStatus();
//if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction
boolean mustAcquire = !isReadAccessAllowed(status);
if (mustAcquire) {
LOG.assertTrue(myTestModeFlag || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction");
assertNoPsiLock();
try {
// timed version of tryLock() respects fairness unlike the no-args method
if (!myLock.readLock().tryLock(0, TimeUnit.MILLISECONDS)) return false;
setReadLockAcquired(status, true);
}
catch (InterruptedException e) {
throw new RuntimeInterruptedException(e);
@@ -1155,6 +1182,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
}
finally {
if (mustAcquire) {
setReadLockAcquired(status, false);
myLock.readLock().unlock();
}
}
@@ -1167,7 +1195,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
if (frame instanceof IdeFrame) {
final IdeFrame ideFrame = (IdeFrame)frame;
if (isActive() != active) {
myActive = Boolean.valueOf(active);
myActive = active;
System.setProperty("idea.active", myActive.toString());
ApplicationActivationListener publisher = getMessageBus().syncPublisher(ApplicationActivationListener.TOPIC);
if (active) {
@@ -1198,10 +1226,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@NotNull
@Override
public AccessToken acquireReadActionLock() {
Status status = getStatus();
// if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction
if (isReadAccessAllowed()) return AccessToken.EMPTY_ACCESS_TOKEN;
if (isReadAccessAllowed(status)) return AccessToken.EMPTY_ACCESS_TOKEN;
return new ReadAccessToken();
return new ReadAccessToken(status);
}
@NotNull
@@ -1215,13 +1244,16 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
public WriteAccessToken(Class _clazz) {
clazz = _clazz;
assertCanRunWriteAction();
assertCanRunWriteAction(getStatus());
ActivityTracker.getInstance().inc();
fireBeforeWriteActionStart(_clazz);
final AtomicBoolean stopped = new AtomicBoolean(false);
LOG.assertTrue(isWriteAccessAllowed() || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing writeAction");
if (!isWriteAccessAllowed()) {
assertNoPsiLock();
}
try {
if (!myLock.writeLock().tryLock()) {
if (ourDumpThreadsOnLongWriteActionWaiting > 0) {
@@ -1304,10 +1336,14 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
}
private class ReadAccessToken extends AccessToken {
private ReadAccessToken() {
assertReadActionAllowed();
private final Status myStatus;
private ReadAccessToken(Status status) {
myStatus = status;
assertNoPsiLock();
try {
myLock.readLock().lockInterruptibly();
setReadLockAcquired(myStatus, true);
acquired();
}
catch (InterruptedException e) {
@@ -1317,13 +1353,18 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public void finish() {
setReadLockAcquired(myStatus, false);
myLock.readLock().unlock();
released();
}
}
private static void assertReadActionAllowed() {
LOG.assertTrue(!Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction");
private final boolean myExtraChecks = isUnitTestMode();
private void assertNoPsiLock() {
if (myExtraChecks) {
LOG.assertTrue(!Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction");
}
}
@Override
@@ -1334,12 +1375,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public boolean isWriteAccessAllowed() {
return myLock.writeLock().isHeldByCurrentThread();
return myLock.isWriteLockedByCurrentThread();
}
@Override
public boolean isWriteActionInProgress() {
return myLock.writeLock().getHoldCount() != 0;
return myLock.getWriteHoldCount() != 0;
}
public void editorPaintStart() {