removed obsolete concurrency primitives

This commit is contained in:
Alexey Kudravtsev
2012-09-12 15:07:31 +04:00
parent 203be7fb3a
commit e9f87ad9a5
24 changed files with 58 additions and 1658 deletions
@@ -48,14 +48,13 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class RefManagerImpl extends RefManager {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.reference.RefManager");
@@ -80,7 +79,7 @@ public class RefManagerImpl extends RefManager {
private final Map<Key, RefManagerExtension> myExtensions = new HashMap<Key, RefManagerExtension>();
private final HashMap<Language, RefManagerExtension> myLanguageExtensions = new HashMap<Language, RefManagerExtension>();
private final JBReentrantReadWriteLock myLock = LockFactory.createReadWriteLock();
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
public RefManagerImpl(Project project, AnalysisScope scope, GlobalInspectionContextImpl context) {
myDeclarationsFound = false;
@@ -1,60 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency.readwrite;
import com.intellij.openapi.application.ApplicationManager;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class AbstractWaiter implements Runnable {
private boolean myFinishedFlag;
public void setFinished(boolean aFinishedFlag) {
myFinishedFlag = aFinishedFlag;
}
private boolean finished() {
return myFinishedFlag;
}
public void run() {
while (!finished()) {
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
return;
}
}
}
public void waitForCompletion() {
waitForCompletion(0);
}
public void waitForCompletion(long aTimeout) {
try {
final Future<?> future = ApplicationManager.getApplication().executeOnPooledThread(this);
if (aTimeout > 0) future.get(aTimeout, TimeUnit.MILLISECONDS);
else future.get();
}
catch (Exception e) {
return;
}
}
}
@@ -1,21 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency.readwrite;
public interface ActiveRunnable {
Object run() throws Throwable;
}
@@ -1,52 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency.readwrite;
public abstract class ActiveRunnableWrapper implements Runnable {
private Object myResult;
private Throwable myException;
public void run() {
try {
myResult = doRun();
}
catch (Throwable aThrowable) {
myException = aThrowable;
}
}
public Object getResult() {
return myResult;
}
private Throwable getException() {
return myException;
}
private boolean hasException() {
return null != getException();
}
public void throwException() throws Throwable {
if (hasException()) {
throw getException();
}
}
public abstract Object doRun() throws Throwable;
}
@@ -1,51 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency.readwrite;
import com.intellij.openapi.command.CommandEvent;
import com.intellij.openapi.command.CommandListener;
import com.intellij.openapi.command.CommandProcessor;
public class CommandWaiter extends AbstractWaiter implements CommandListener {
private final Runnable myCommandRunnable;
public CommandWaiter(Runnable aCommandRunnable) {
myCommandRunnable = aCommandRunnable;
setFinished(false);
CommandProcessor.getInstance().addCommandListener(this);
}
public void beforeCommandFinished(CommandEvent event) {
}
public void commandFinished(CommandEvent event) {
if (event.getCommand() == myCommandRunnable) {
CommandProcessor.getInstance().removeCommandListener(this);
setFinished(true);
}
}
public void commandStarted(CommandEvent event) {
}
public void undoTransparentActionStarted() {
}
public void undoTransparentActionFinished() {
}
}
@@ -1,59 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency.readwrite;
import com.intellij.openapi.application.ApplicationListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.wm.IdeFrame;
public class WriteActionWaiter extends AbstractWaiter implements ApplicationListener {
private final Runnable myActionRunnable;
public WriteActionWaiter(Runnable aActionRunnable) {
myActionRunnable = aActionRunnable;
setFinished(false);
ApplicationManager.getApplication().addApplicationListener(this);
}
public void writeActionFinished(Object aRunnable) {
if (aRunnable == myActionRunnable) {
setFinished(true);
ApplicationManager.getApplication().removeApplicationListener(this);
}
}
public void applicationExiting() {
}
public void beforeWriteActionStart(Object action) {
}
public boolean canExitApplication() {
return true;
}
public void writeActionStarted(Object action) {
}
public void applicationActivated(IdeFrame ideFrame) {
}
public void applicationDeactivated(IdeFrame ideFrame) {
}
}
@@ -1,90 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency.readwrite;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.project.Project;
import javax.swing.*;
import java.awt.*;
public abstract class WriteActionWorker extends ActiveRunnableWrapper {
private void start() {
WriteActionWaiter waiter = new WriteActionWaiter(this);
if (EventQueue.isDispatchThread()) {
ApplicationManager.getApplication().runWriteAction(WriteActionWorker.this);
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ApplicationManager.getApplication().runWriteAction(WriteActionWorker.this);
}
});
}
waiter.waitForCompletion();
}
public static Object run(final ActiveRunnable aActiveRunnable) throws Throwable {
WriteActionWorker worker = new WriteActionWorker() {
public Object doRun() throws Throwable {
return aActiveRunnable.run();
}
};
worker.start();
worker.throwException();
return worker.getResult();
}
private static class CommandWrapper extends ActiveRunnableWrapper {
private final ActiveRunnable myWriteActionRunnable;
public CommandWrapper(ActiveRunnable aWriteActionRunnable) {
myWriteActionRunnable = aWriteActionRunnable;
}
public Object doRun() throws Throwable {
return WriteActionWorker.run(myWriteActionRunnable);
}
}
public static Object runInCommand(final Project project, final ActiveRunnable aActiveRunnable, final String aCommandName) throws Throwable {
final CommandWrapper commandWrapper = new CommandWrapper(aActiveRunnable);
CommandWaiter commandWaiter = new CommandWaiter(commandWrapper);
if (EventQueue.isDispatchThread()) {
CommandProcessor.getInstance().executeCommand(project, commandWrapper, aCommandName, null);
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CommandProcessor.getInstance().executeCommand(project, commandWrapper, aCommandName, null);
}
});
}
commandWaiter.waitForCompletion();
commandWrapper.throwException();
return commandWrapper.getResult();
}
}
@@ -30,9 +30,6 @@ import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.util.io.ByteSequence;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.concurrency.JBLock;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import com.intellij.util.containers.IntArrayList;
import com.intellij.util.io.*;
import com.intellij.util.io.DataOutputStream;
@@ -46,6 +43,7 @@ import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@SuppressWarnings({"PointlessArithmeticExpression", "HardCodedStringLiteral"})
public class FSRecords implements Forceable {
@@ -87,8 +85,8 @@ public class FSRecords implements Forceable {
private static final String CHILDREN_ATT = "FsRecords.DIRECTORY_CHILDREN";
private static final JBLock r;
private static final JBLock w;
private static final ReentrantReadWriteLock.ReadLock r;
private static final ReentrantReadWriteLock.WriteLock w;
private static volatile int ourLocalModificationCount = 0;
private static volatile boolean ourIsDisposed;
@@ -100,12 +98,12 @@ public class FSRecords implements Forceable {
//noinspection ConstantConditions
assert HEADER_SIZE <= RECORD_SIZE;
JBReentrantReadWriteLock lock = LockFactory.createReadWriteLock();
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
r = lock.readLock();
w = lock.writeLock();
}
private static class DbConnection {
static class DbConnection {
private static boolean ourInitialized;
private static final TObjectIntHashMap<String> myAttributeIds = new TObjectIntHashMap<String>();
@@ -411,7 +409,7 @@ public class FSRecords implements Forceable {
myRecords.putInt(HEADER_CONNECTION_STATUS_OFFSET, SAFELY_CLOSED_MAGIC);
}
public static void cleanRecord(final int id) {
static void cleanRecord(int id) {
myRecords.put(id * RECORD_SIZE, ZEROES, 0, RECORD_SIZE);
}
@@ -615,7 +613,7 @@ public class FSRecords implements Forceable {
}
}
private static void addToFreeRecordsList(int id) {
static void addToFreeRecordsList(int id) {
DbConnection.addFreeRecord(id);
setFlags(id, FREE_RECORD_FLAG, false);
}
@@ -1409,14 +1407,14 @@ public class FSRecords implements Forceable {
final IntArrayList validAttributeIds) {
int parentId = getParent(id);
assert parentId >= 0 && parentId < recordCount;
if (parentId > 0) {
final int parentFlags = getFlags(parentId);
assert (parentFlags & FREE_RECORD_FLAG) == 0;
assert (parentFlags & PersistentFS.IS_DIRECTORY_FLAG) != 0;
if (parentId > 0 && getParent(parentId) > 0) {
int parentFlags = getFlags(parentId);
assert (parentFlags & FREE_RECORD_FLAG) == 0 : parentId + ": "+Integer.toHexString(parentFlags);
assert (parentFlags & PersistentFS.IS_DIRECTORY_FLAG) != 0 : parentId + ": "+Integer.toHexString(parentFlags);
}
String name = getName(id);
LOG.assertTrue(parentId == 0 || name.length() > 0, "File with empty name found under " + getName(parentId) + ", id=" + id);
LOG.assertTrue(parentId == 0 || !name.isEmpty(), "File with empty name found under " + getName(parentId) + ", id=" + id);
checkContentsStorageSanity(id);
checkAttributesStorageSanity(id, usedAttributeRecordIds, validAttributeIds);
@@ -1460,7 +1458,7 @@ public class FSRecords implements Forceable {
assert !usedAttributeRecordIds.contains(attDataRecordId);
usedAttributeRecordIds.add(attDataRecordId);
if (!validAttributeIds.contains(attId)) {
assert getNames().valueOf(attId).length() > 0;
assert !getNames().valueOf(attId).isEmpty();
validAttributeIds.add(attId);
}
getAttributesStorage().checkSanity(attDataRecordId);
@@ -28,8 +28,6 @@ import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.SystemProperties;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import gnu.trove.THashSet;
@@ -38,6 +36,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author dsl
@@ -46,7 +45,7 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent,
private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.PathMacrosImpl");
private final Map<String, String> myLegacyMacros = new HashMap<String, String>();
private final Map<String, String> myMacros = new HashMap<String, String>();
private final JBReentrantReadWriteLock myLock = LockFactory.createReadWriteLock();
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
private final List<String> myIgnoredMacros = ContainerUtil.createEmptyCOWList();
@NonNls
@@ -74,13 +74,6 @@ public class Patches {
*/
public static final boolean APPLE_BUG_ID_3716835 = SystemInfo.isMac && !SystemInfo.isJavaVersionAtLeast("1.4.2.5");
/**
* Use of JDK1.5 ReentrantReadWriteLock API eventually leads to JVM lock-up or core dump crashes.
* With this flag true, API is wrapped with alternative implementation via early days Doug Lea's API.
* @see com.intellij.util.concurrency.LockFactory
*/
public static final boolean APPLE_BUG_ID_5359442 = SystemInfo.isMac && (!SystemInfo.isMacOSLeopard || !SystemInfo.isJavaVersionAtLeast("1.5.0_16"));
/**
* Lion eAWT FullScreen mode leads to visual artifacts.
*/
@@ -16,17 +16,15 @@
package com.intellij.openapi.util;
import com.intellij.util.concurrency.JBLock;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public abstract class FieldCache<T, Owner,AccessorParameter,Parameter> {
private static final RecursionGuard ourGuard = RecursionManager.createGuard("fieldCache");
private final JBLock r;
private final JBLock w;
private final ReentrantReadWriteLock.ReadLock r;
private final ReentrantReadWriteLock.WriteLock w;
protected FieldCache() {
JBReentrantReadWriteLock ourLock = LockFactory.createReadWriteLock();
ReentrantReadWriteLock ourLock = new ReentrantReadWriteLock();
r = ourLock.readLock();
w = ourLock.writeLock();
}
@@ -1,38 +0,0 @@
/*
* Copyright 2000-2009 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.
*/
/*
* @author max
*/
package com.intellij.util.concurrency;
import java.util.concurrent.locks.Lock;
public class DefaultLockAdapter implements JBLock {
private final Lock myAdaptee;
public DefaultLockAdapter(final Lock adaptee) {
myAdaptee = adaptee;
}
public void lock() {
myAdaptee.lock();
}
public void unlock() {
myAdaptee.unlock();
}
}
@@ -1,46 +0,0 @@
/*
* Copyright 2000-2009 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.
*/
/*
* @author max
*/
package com.intellij.util.concurrency;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class DefaultReentrantReadWriteLockAdapter implements JBReentrantReadWriteLock {
private final DefaultLockAdapter myReadLock;
private final DefaultLockAdapter myWriteLock;
private final ReentrantReadWriteLock myAdaptee;
public DefaultReentrantReadWriteLockAdapter() {
myAdaptee = new ReentrantReadWriteLock();
myReadLock = new DefaultLockAdapter(myAdaptee.readLock());
myWriteLock = new DefaultLockAdapter(myAdaptee.writeLock());
}
public JBLock readLock() {
return myReadLock;
}
public JBLock writeLock() {
return myWriteLock;
}
public boolean isWriteLockedByCurrentThread() {
return myAdaptee.isWriteLockedByCurrentThread();
}
}
@@ -1,25 +0,0 @@
/*
* Copyright 2000-2009 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.
*/
/*
* @author max
*/
package com.intellij.util.concurrency;
public interface JBLock {
void lock();
void unlock();
}
@@ -1,29 +0,0 @@
/*
* Copyright 2000-2009 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.
*/
/*
* @author max
*/
package com.intellij.util.concurrency;
/**
* @see LockFactory
*/
public interface JBReentrantReadWriteLock {
JBLock readLock();
JBLock writeLock();
boolean isWriteLockedByCurrentThread();
}
@@ -1,35 +0,0 @@
/*
* Copyright 2000-2009 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.
*/
/*
* @author max
*/
package com.intellij.util.concurrency;
import com.intellij.Patches;
public class LockFactory {
private LockFactory() {}
public static JBReentrantReadWriteLock createReadWriteLock() {
if (Patches.APPLE_BUG_ID_5359442) {
return new SynchronizedBasedReentrantReadWriteLock();
}
else {
return new DefaultReentrantReadWriteLockAdapter();
}
}
}
@@ -1,84 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency;
/**
* ReadWriteLocks maintain a pair of associated locks.
* The readLock may be held simultanously by multiple
* reader threads, so long as there are no writers. The writeLock
* is exclusive. ReadWrite locks are generally preferable to
* plain Sync locks or synchronized methods in cases where:
* <ul>
* <li> The methods in a class can be cleanly separated into
* those that only access (read) data vs those that
* modify (write).
* <li> Target applications generally have more readers than writers.
* <li> The methods are relatively time-consuming (as a rough
* rule of thumb, exceed more than a hundred instructions), so it
* pays to introduce a bit more overhead associated with
* ReadWrite locks compared to simple synchronized methods etc
* in order to allow concurrency among reader threads.
*
* </ul>
* Different implementation classes differ in policies surrounding
* which threads to prefer when there is
* contention. By far, the most commonly useful policy is
* WriterPreferenceReadWriteLock. The other implementations
* are targeted for less common, niche applications.
*<p>
* Standard usage:
* <pre>
* class X {
* ReadWriteLock rw;
* // ...
*
* public void read() throws InterruptedException {
* rw.readLock().acquire();
* try {
* // ... do the read
* }
* finally {
* rw.readlock().release()
* }
* }
*
*
* public void write() throws InterruptedException {
* rw.writeLock().acquire();
* try {
* // ... do the write
* }
* finally {
* rw.writelock().release()
* }
* }
* }
* </pre>
* @see Sync
* <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
**/
public interface ReadWriteLock {
/** get the readLock **/
Sync readLock();
/** get the writeLock **/
Sync writeLock();
}
@@ -1,233 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency;
import gnu.trove.TIntArrayList;
import java.util.ArrayList;
/**
* A writer-preference ReadWriteLock that allows both readers and
* writers to reacquire
* read or write locks in the style of a ReentrantLock.
* Readers are not allowed until all write locks held by
* the writing thread have been released.
* Among other applications, reentrancy can be useful when
* write locks are held during calls or callbacks to methods that perform
* reads under read locks.
* <p>
* <b>Sample usage</b>. Here is a code sketch showing how to exploit
* reentrancy to perform lock downgrading after updating a cache:
* <pre>
* class CachedData {
* Object data;
* volatile boolean cacheValid;
* ReentrantWriterPreferenceReadWriteLock rwl = ...
*
* void processCachedData() {
* rwl.readLock().acquire();
* if (!cacheValid) {
*
* // upgrade lock:
* rwl.readLock().release(); // must release first to obtain writelock
* rwl.writeLock().acquire();
* if (!cacheValid) { // recheck
* data = ...
* cacheValid = true;
* }
* // downgrade lock
* rwl.readLock().acquire(); // reacquire read without giving up lock
* rwl.writeLock().release(); // release write, still hold read
* }
*
* use(data);
* rwl.readLock().release();
* }
* }
* </pre>
*
*
* <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
**/
public class ReentrantWriterPreferenceReadWriteLock extends WriterPreferenceReadWriteLock {
/** Number of acquires on write lock by activeWriter_ thread **/
private long writeHolds_ = 0;
private final ThreadToCountMap readers_ = new ThreadToCountMap();
private final ThreadLocal<Boolean> hasReadLock = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
private final ThreadLocal<Boolean> hasWriteLock = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
public boolean isReadLockAcquired() {
return hasReadLock.get();
}
public boolean isWriteLockAcquired() {
return hasWriteLock.get();
}
public synchronized boolean isReadLockAcquired(Thread thread){
return readers_.get(thread) > 0;
}
public synchronized boolean isWriteLockAcquired(Thread thread){
return activeWriter_ == thread;
}
protected boolean allowReader() {
// [Valentin] Changed policy so that readers are allowed while there are waiting writers
// [cdr]: No more!
return (activeWriter_ == null && waitingWriters_ == 0) ||
activeWriter_ == Thread.currentThread();
}
protected synchronized boolean startRead() {
Thread t = Thread.currentThread();
int c = readers_.get(t);
if (c > 0) { // already held -- just increment hold count
readers_.put(t, c + 1);
++activeReaders_;
return true;
}
else if (allowReader()) {
hasReadLock.set(true);
readers_.put(t, 1);
++activeReaders_;
return true;
}
else
return false;
}
protected synchronized boolean startWrite() {
if (activeWriter_ == Thread.currentThread()) { // already held; re-acquire
++writeHolds_;
return true;
}
else if (writeHolds_ == 0) {
if (activeReaders_ == 0 ||
(readers_.size() == 1 &&
readers_.get(Thread.currentThread()) > 0)) {
activeWriter_ = Thread.currentThread();
hasWriteLock.set(true);
writeHolds_ = 1;
return true;
}
else
return false;
}
else
return false;
}
protected synchronized Signaller endRead() {
--activeReaders_;
Thread t = Thread.currentThread();
int c = readers_.get(t);
if (c != 1) { // more than one hold; decrement count
readers_.put(t, c - 1);
return null;
}
else {
readers_.put(t, 0);
hasReadLock.set(false);
if (writeHolds_ > 0) { // a write lock is still held by current thread
return null;
}
else if (/*activeReaders_ == 0 && */activeReaders_ <= 1 && waitingWriters_ > 0) {
// [Valentin] commented out check for activeReaders == 0 - it's incorrect when waiting writer is already a reader!!
return writerLock_;
}
else{
return null;
}
}
}
protected synchronized Signaller endWrite() {
--writeHolds_;
if (writeHolds_ > 0) // still being held
return null;
else {
activeWriter_ = null;
hasWriteLock.set(false);
if (waitingReaders_ > 0 && allowReader())
return readerLock_;
else if (waitingWriters_ > 0)
return writerLock_;
else
return null;
}
}
private static final class ThreadToCountMap{
private final ArrayList<Thread> myThreads = new ArrayList<Thread>();
private final TIntArrayList myCounters = new TIntArrayList();
private Thread myLastThread = null; // optimization
private int myLastCounter;
public int get(Thread thread){
if (thread == myLastThread) return myLastCounter;
int index = myThreads.indexOf(thread);
int result = index >= 0 ? myCounters.getQuick(index) : 0;
myLastThread = thread;
myLastCounter = result;
return result;
}
public void put(Thread thread, int count){
myLastThread = null;
int index = myThreads.indexOf(thread);
if (index >= 0){
if (count == 0){
myThreads.remove(index);
myCounters.remove(index);
}
else{
myCounters.setQuick(index, count);
}
}
else{
if (count != 0){
myThreads.add(thread);
myCounters.add(count);
}
}
}
public int size(){
return myThreads.size();
}
}
}
@@ -1,340 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency;
/**
* Main interface for locks, gates, and conditions.
* <p>
* Sync objects isolate waiting and notification for particular
* logical states, resource availability, events, and the like that are
* shared across multiple threads. Use of Syncs sometimes
* (but by no means always) adds flexibility and efficiency
* compared to the use of plain java monitor methods
* and locking, and are sometimes (but by no means always)
* simpler to program with.
* <p>
*
* Most Syncs are intended to be used primarily (although
* not exclusively) in before/after constructions such as:
* <pre>
* class X {
* Sync gate;
* // ...
*
* public void m() {
* try {
* gate.acquire(); // block until condition holds
* try {
* // ... method body
* }
* finally {
* gate.release()
* }
* }
* catch (InterruptedException ex) {
* // ... evasive action
* }
* }
*
* public void m2(Sync cond) { // use supplied condition
* try {
* if (cond.attempt(10)) { // try the condition for 10 ms
* try {
* // ... method body
* }
* finally {
* cond.release()
* }
* }
* }
* catch (InterruptedException ex) {
* // ... evasive action
* }
* }
* }
* </pre>
* Syncs may be used in somewhat tedious but more flexible replacements
* for built-in Java synchronized blocks. For example:
* <pre>
* class HandSynched {
* private double state_ = 0.0;
* private final Sync lock; // use lock type supplied in constructor
* public HandSynched(Sync l) { lock = l; }
*
* public void changeState(double d) {
* try {
* lock.acquire();
* try { state_ = updateFunction(d); }
* finally { lock.release(); }
* }
* catch(InterruptedException ex) { }
* }
*
* public double getState() {
* double d = 0.0;
* try {
* lock.acquire();
* try { d = accessFunction(state_); }
* finally { lock.release(); }
* }
* catch(InterruptedException ex){}
* return d;
* }
* private double updateFunction(double d) { ... }
* private double accessFunction(double d) { ... }
* }
* </pre>
* If you have a lot of such methods, and they take a common
* form, you can standardize this using wrappers. Some of these
* wrappers are standardized in LockedExecutor, but you can make others.
* For example:
* <pre>
* class HandSynchedV2 {
* private double state_ = 0.0;
* private final Sync lock; // use lock type supplied in constructor
* public HandSynchedV2(Sync l) { lock = l; }
*
* protected void runSafely(Runnable r) {
* try {
* lock.acquire();
* try { r.run(); }
* finally { lock.release(); }
* }
* catch (InterruptedException ex) { // propagate without throwing
* Thread.currentThread().interrupt();
* }
* }
*
* public void changeState(double d) {
* runSafely(new Runnable() {
* public void run() { state_ = updateFunction(d); }
* });
* }
* // ...
* }
* </pre>
* <p>
* One reason to bother with such constructions is to use deadlock-
* avoiding back-offs when dealing with locks involving multiple objects.
* For example, here is a Cell class that uses attempt to back-off
* and retry if two Cells are trying to swap values with each other
* at the same time.
* <pre>
* class Cell {
* long value;
* Sync lock = ... // some sync implementation class
* void swapValue(Cell other) {
* for (;;) {
* try {
* lock.acquire();
* try {
* if (other.lock.attempt(100)) {
* try {
* long t = value;
* value = other.value;
* other.value = t;
* return;
* }
* finally { other.lock.release(); }
* }
* }
* finally { lock.release(); }
* }
* catch (InterruptedException ex) { return; }
* }
* }
* }
*</pre>
* <p>
* Here is an even fancier version, that uses lock re-ordering
* upon conflict:
* <pre>
* class Cell {
* long value;
* Sync lock = ...;
* private static boolean trySwap(Cell a, Cell b) {
* a.lock.acquire();
* try {
* if (!b.lock.attempt(0))
* return false;
* try {
* long t = a.value;
* a.value = b.value;
* b.value = t;
* return true;
* }
* finally { other.lock.release(); }
* }
* finally { lock.release(); }
* return false;
* }
*
* void swapValue(Cell other) {
* try {
* while (!trySwap(this, other) &&
* !tryswap(other, this))
* Thread.sleep(1);
* }
* catch (InterruptedException ex) { return; }
* }
*}
*</pre>
* <p>
* Interruptions are in general handled as early as possible.
* Normally, InterruptionExceptions are thrown
* in acquire and attempt(msec) if interruption
* is detected upon entry to the method, as well as in any
* later context surrounding waits.
* However, interruption status is ignored in release();
* <p>
* Timed versions of attempt report failure via return value.
* If so desired, you can transform such constructions to use exception
* throws via
* <pre>
* if (!c.attempt(timeval)) throw new TimeoutException(timeval);
* </pre>
* <p>
* The TimoutSync wrapper class can be used to automate such usages.
* <p>
* All time values are expressed in milliseconds as longs, which have a maximum
* value of Long.MAX_VALUE, or almost 300,000 centuries. It is not
* known whether JVMs actually deal correctly with such extreme values.
* For convenience, some useful time values are defined as static constants.
* <p>
* All implementations of the three Sync methods guarantee to
* somehow employ Java <code>synchronized</code> methods or blocks,
* and so entail the memory operations described in JLS
* chapter 17 which ensure that variables are loaded and flushed
* within before/after constructions.
* <p>
* Syncs may also be used in spinlock constructions. Although
* it is normally best to just use acquire(), various forms
* of busy waits can be implemented. For a simple example
* (but one that would probably never be preferable to using acquire()):
* <pre>
* class X {
* Sync lock = ...
* void spinUntilAcquired() throws InterruptedException {
* // Two phase.
* // First spin without pausing.
* int purespins = 10;
* for (int i = 0; i < purespins; ++i) {
* if (lock.attempt(0))
* return true;
* }
* // Second phase - use timed waits
* long waitTime = 1; // 1 millisecond
* for (;;) {
* if (lock.attempt(waitTime))
* return true;
* else
* waitTime = waitTime * 3 / 2 + 1; // increase 50%
* }
* }
* }
* </pre>
* <p>
* In addition pure synchronization control, Syncs
* may be useful in any context requiring before/after methods.
* For example, you can use an ObservableSync
* (perhaps as part of a LayeredSync) in order to obtain callbacks
* before and after each method invocation for a given class.
* <p>
* <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
**/
public interface Sync {
/**
* Wait (possibly forever) until successful passage.
* Fail only upon interuption. Interruptions always result in
* `clean' failures. On failure, you can be sure that it has not
* been acquired, and that no
* corresponding release should be performed. Conversely,
* a normal return guarantees that the acquire was successful.
**/
void acquire() throws InterruptedException;
/**
* Wait at most msecs to pass; report whether passed.
* <p>
* The method has best-effort semantics:
* The msecs bound cannot
* be guaranteed to be a precise upper bound on wait time in Java.
* Implementations generally can only attempt to return as soon as possible
* after the specified bound. Also, timers in Java do not stop during garbage
* collection, so timeouts can occur just because a GC intervened.
* So, msecs arguments should be used in
* a coarse-grained manner. Further,
* implementations cannot always guarantee that this method
* will return at all without blocking indefinitely when used in
* unintended ways. For example, deadlocks may be encountered
* when called in an unintended context.
* <p>
* @param msecs the number of milleseconds to wait.
* An argument less than or equal to zero means not to wait at all.
* However, this may still require
* access to a synchronization lock, which can impose unbounded
* delay if there is a lot of contention among threads.
* @return true if acquired
**/
boolean attempt(long msecs) throws InterruptedException;
/**
* Potentially enable others to pass.
* <p>
* Because release does not raise exceptions,
* it can be used in `finally' clauses without requiring extra
* embedded try/catch blocks. But keep in mind that
* as with any java method, implementations may
* still throw unchecked exceptions such as Error or NullPointerException
* when faced with uncontinuable errors. However, these should normally
* only be caught by higher-level error handlers.
**/
void release();
/** One second, in milliseconds; convenient as a time-out value **/
long ONE_SECOND = 1000;
/** One minute, in milliseconds; convenient as a time-out value **/
long ONE_MINUTE = 60 * ONE_SECOND;
/** One hour, in milliseconds; convenient as a time-out value **/
long ONE_HOUR = 60 * ONE_MINUTE;
/** One day, in milliseconds; convenient as a time-out value **/
long ONE_DAY = 24 * ONE_HOUR;
/** One week, in milliseconds; convenient as a time-out value **/
long ONE_WEEK = 7 * ONE_DAY;
/** One year in milliseconds; convenient as a time-out value **/
// Not that it matters, but there is some variation across
// standard sources about value at msec precision.
// The value used is the same as in java.util.GregorianCalendar
long ONE_YEAR = (long)(365.2425 * ONE_DAY);
/** One century in milliseconds; convenient as a time-out value **/
long ONE_CENTURY = 100 * ONE_YEAR;
}
@@ -1,41 +0,0 @@
/*
* Copyright 2000-2009 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.
*/
/*
* @author max
*/
package com.intellij.util.concurrency;
public class SyncAdapterLock implements JBLock {
private final Sync myAdaptee;
public SyncAdapterLock(final Sync adaptee) {
myAdaptee = adaptee;
}
public void lock() {
try {
myAdaptee.acquire();
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void unlock() {
myAdaptee.release();
}
}
@@ -1,44 +0,0 @@
/*
* Copyright 2000-2009 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.
*/
/*
* @author max
*/
package com.intellij.util.concurrency;
public class SynchronizedBasedReentrantReadWriteLock implements JBReentrantReadWriteLock {
private final SyncAdapterLock myReadLock;
private final SyncAdapterLock myWriteLock;
private final ReentrantWriterPreferenceReadWriteLock myAdaptee;
public SynchronizedBasedReentrantReadWriteLock() {
myAdaptee = new ReentrantWriterPreferenceReadWriteLock();
myReadLock = new SyncAdapterLock(myAdaptee.readLock());
myWriteLock = new SyncAdapterLock(myAdaptee.writeLock());
}
public JBLock readLock() {
return myReadLock;
}
public JBLock writeLock() {
return myWriteLock;
}
public boolean isWriteLockedByCurrentThread() {
return myAdaptee.isWriteLockAcquired(Thread.currentThread());
}
}
@@ -1,315 +0,0 @@
/*
* Copyright 2000-2009 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.util.concurrency;
/**
* A ReadWriteLock that prefers waiting writers over
* waiting readers when there is contention. This class
* is adapted from the versions described in CPJ, improving
* on the ones there a bit by segregating reader and writer
* wait queues, which is typically more efficient.
* <p>
* The locks are <em>NOT</em> reentrant. In particular,
* even though it may appear to usually work OK,
* a thread holding a read lock should not attempt to
* re-acquire it. Doing so risks lockouts when there are
* also waiting writers.
* <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
**/
public class WriterPreferenceReadWriteLock implements ReadWriteLock {
protected long activeReaders_ = 0;
protected Thread activeWriter_ = null;
protected long waitingReaders_ = 0;
protected long waitingWriters_ = 0;
protected final ReaderLock readerLock_ = new ReaderLock();
protected final WriterLock writerLock_ = new WriterLock();
public Sync writeLock() { return writerLock_; }
public Sync readLock() { return readerLock_; }
/*
A bunch of small synchronized methods are needed
to allow communication from the Lock objects
back to this object, that serves as controller
*/
protected synchronized void cancelledWaitingReader() { --waitingReaders_; }
protected synchronized void cancelledWaitingWriter() { --waitingWriters_; }
/** Override this method to change to reader preference **/
protected boolean allowReader() {
return activeWriter_ == null && waitingWriters_ == 0;
}
protected synchronized boolean startRead() {
boolean allowRead = allowReader();
if (allowRead) ++activeReaders_;
return allowRead;
}
protected synchronized boolean startWrite() {
// The allowWrite expression cannot be modified without
// also changing startWrite, so is hard-wired
boolean allowWrite = activeWriter_ == null && activeReaders_ == 0;
if (allowWrite) activeWriter_ = Thread.currentThread();
return allowWrite;
}
/*
Each of these variants is needed to maintain atomicity
of wait counts during wait loops. They could be
made faster by manually inlining each other. We hope that
compilers do this for us though.
*/
protected synchronized boolean startReadFromNewReader() {
boolean pass = startRead();
if (!pass) ++waitingReaders_;
return pass;
}
protected synchronized boolean startWriteFromNewWriter() {
boolean pass = startWrite();
if (!pass) ++waitingWriters_;
return pass;
}
protected synchronized boolean startReadFromWaitingReader() {
boolean pass = startRead();
if (pass) --waitingReaders_;
return pass;
}
protected synchronized boolean startWriteFromWaitingWriter() {
boolean pass = startWrite();
if (pass) --waitingWriters_;
return pass;
}
/**
* Called upon termination of a read.
* Returns the object to signal to wake up a waiter, or null if no such
**/
protected synchronized Signaller endRead() {
if (--activeReaders_ == 0 && waitingWriters_ > 0)
return writerLock_;
else
return null;
}
/**
* Called upon termination of a write.
* Returns the object to signal to wake up a waiter, or null if no such
**/
protected synchronized Signaller endWrite() {
activeWriter_ = null;
if (waitingReaders_ > 0 && allowReader())
return readerLock_;
else if (waitingWriters_ > 0)
return writerLock_;
else
return null;
}
/**
* Reader and Writer requests are maintained in two different
* wait sets, by two different objects. These objects do not
* know whether the wait sets need notification since they
* don't know preference rules. So, each supports a
* method that can be selected by main controlling object
* to perform the notifications. This base class simplifies mechanics.
**/
protected abstract static class Signaller { // base for ReaderLock and WriterLock
abstract void signalWaiters();
}
protected class ReaderLock extends Signaller implements Sync {
public void acquire() throws InterruptedException {
//TODO: [not sure why this is necessary but very inperformant] if (Thread.interrupted()) throw new InterruptedException();
InterruptedException ie = null;
synchronized(this) {
if (!startReadFromNewReader()) {
for (;;) {
try {
wait();
if (startReadFromWaitingReader())
return;
}
catch(InterruptedException ex){
cancelledWaitingReader();
ie = ex;
break;
}
}
}
}
if (ie != null) {
// fall through outside synch on interrupt.
// This notification is not really needed here,
// but may be in plausible subclasses
writerLock_.signalWaiters();
throw ie;
}
}
public void release() {
Signaller s = endRead();
if (s != null) s.signalWaiters();
}
synchronized void signalWaiters() {
notifyAll(); }
public boolean attempt(long msecs) throws InterruptedException {
//TODO: [not sure why this is necessary but very inperformant] if (Thread.interrupted()) throw new InterruptedException();
InterruptedException ie = null;
synchronized(this) {
if (msecs <= 0)
return startRead();
else if (startReadFromNewReader())
return true;
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
for (;;) {
try {
wait(waitTime); }
catch(InterruptedException ex){
cancelledWaitingReader();
ie = ex;
break;
}
if (startReadFromWaitingReader())
return true;
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0) {
cancelledWaitingReader();
break;
}
}
}
}
}
// safeguard on interrupt or timeout:
writerLock_.signalWaiters();
if (ie != null) throw ie;
else return false; // timed out
}
}
protected class WriterLock extends Signaller implements Sync {
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
InterruptedException ie = null;
synchronized(this) {
if (!startWriteFromNewWriter()) {
for (;;) {
try {
wait();
if (startWriteFromWaitingWriter())
return;
}
catch(InterruptedException ex){
cancelledWaitingWriter();
notify();
ie = ex;
break;
}
}
}
}
if (ie != null) {
// Fall through outside synch on interrupt.
// On exception, we may need to signal readers.
// It is not worth checking here whether it is strictly necessary.
readerLock_.signalWaiters();
throw ie;
}
}
public void release(){
Signaller s = endWrite();
if (s != null) s.signalWaiters();
}
synchronized void signalWaiters() {
notify(); }
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
InterruptedException ie = null;
synchronized(this) {
if (msecs <= 0)
return startWrite();
else if (startWriteFromNewWriter())
return true;
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
for (;;) {
try {
wait(waitTime); }
catch(InterruptedException ex){
cancelledWaitingWriter();
notify();
ie = ex;
break;
}
if (startWriteFromWaitingWriter())
return true;
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0) {
cancelledWaitingWriter();
notify();
break;
}
}
}
}
}
readerLock_.signalWaiters();
if (ie != null) throw ie;
else return false; // timed out
}
}
}
@@ -20,21 +20,30 @@
package com.intellij.util.containers;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.concurrency.JBLock;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements ConcurrentMap<K, V> {
private final JBLock r;
private final JBLock w;
private final Lock r;
private final Lock w;
private static final StripedLockHolder<ReentrantReadWriteLock> LOCKS = new StripedLockHolder<ReentrantReadWriteLock>(ReentrantReadWriteLock.class) {
@NotNull
@Override
protected ReentrantReadWriteLock create() {
return new ReentrantReadWriteLock();
}
};
{
final JBReentrantReadWriteLock mutex = StripedJBReentrantReadWriteLocks.getInstance().allocateLock();
final ReentrantReadWriteLock mutex = LOCKS.allocateLock();
r = mutex.readLock();
w = mutex.writeLock();
}
@@ -49,6 +58,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
super(initialCapacity, loadFactor);
}
@Override
public int size() {
r.lock();
try {
@@ -59,6 +69,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public boolean isEmpty() {
r.lock();
try {
@@ -69,6 +80,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public boolean containsKey(Object key) {
r.lock();
try {
@@ -79,6 +91,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public boolean containsValue(Object value) {
r.lock();
try {
@@ -89,6 +102,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public V get(Object key) {
r.lock();
try {
@@ -99,6 +113,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public V put(K key, V value) {
w.lock();
try {
@@ -109,6 +124,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public V remove(Object key) {
w.lock();
try {
@@ -119,6 +135,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
w.lock();
try {
@@ -129,6 +146,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public void clear() {
w.lock();
try {
@@ -139,6 +157,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public LockPoolSynchronizedMap<K, V> clone() {
r.lock();
try {
@@ -149,6 +168,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public Set<K> keySet() {
r.lock();
try {
@@ -159,6 +179,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public Set<Map.Entry<K, V>> entrySet() {
r.lock();
try {
@@ -169,6 +190,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
@Override
public Collection<V> values() {
r.lock();
try {
@@ -179,7 +201,8 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
public boolean replace(K key, V oldValue, V newValue) {
@Override
public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) {
w.lock();
try {
V prev = get(key);
@@ -187,12 +210,7 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
return false;
}
if (newValue == null) {
remove(key);
}
else {
put(key, newValue);
}
put(key, newValue);
return true;
}
finally {
@@ -200,17 +218,13 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
public V replace(K key, V newValue) {
@Override
public V replace(@NotNull K key, @NotNull V newValue) {
w.lock();
try {
V prev = get(key);
if (newValue == null) {
remove(key);
}
else {
put(key, newValue);
}
put(key, newValue);
return prev;
}
finally {
@@ -218,7 +232,8 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
public V putIfAbsent(K key, V value) {
@Override
public V putIfAbsent(@NotNull K key, V value) {
w.lock();
try {
V prev = get(key);
@@ -235,7 +250,8 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
}
}
public boolean remove(Object key, Object oldValue) {
@Override
public boolean remove(@NotNull Object key, Object oldValue) {
w.lock();
try {
V currentValue = get(key);
@@ -1,40 +0,0 @@
/*
* Copyright 2000-2010 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.util.containers;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
public final class StripedJBReentrantReadWriteLocks extends StripedLockHolder<JBReentrantReadWriteLock> {
private StripedJBReentrantReadWriteLocks() {
super(JBReentrantReadWriteLock.class);
}
@NotNull
@Override
protected JBReentrantReadWriteLock create() {
return LockFactory.createReadWriteLock();
}
private static final StripedJBReentrantReadWriteLocks INSTANCE = new StripedJBReentrantReadWriteLocks();
public static StripedJBReentrantReadWriteLocks getInstance() {
return INSTANCE;
}
}