提交 b22391ba 编写于 作者: M malenkov

8023310: Thread contention in the method Beans.IsDesignTime()

Reviewed-by: art, sfriberg
上级 6b21a48b
...@@ -41,24 +41,20 @@ import java.util.WeakHashMap; ...@@ -41,24 +41,20 @@ import java.util.WeakHashMap;
*/ */
final class ThreadGroupContext { final class ThreadGroupContext {
private static final WeakIdentityMap<ThreadGroupContext> contexts = new WeakIdentityMap<>(); private static final WeakIdentityMap<ThreadGroupContext> contexts = new WeakIdentityMap<ThreadGroupContext>() {
protected ThreadGroupContext create(Object key) {
return new ThreadGroupContext();
}
};
/** /**
* Returns the appropriate {@code AppContext} for the caller, * Returns the appropriate {@code ThreadGroupContext} for the caller,
* as determined by its {@code ThreadGroup}. * as determined by its {@code ThreadGroup}.
* *
* @return the application-dependent context * @return the application-dependent context
*/ */
static ThreadGroupContext getContext() { static ThreadGroupContext getContext() {
ThreadGroup group = Thread.currentThread().getThreadGroup(); return contexts.get(Thread.currentThread().getThreadGroup());
synchronized (contexts) {
ThreadGroupContext context = contexts.get(group);
if (context == null) {
context = new ThreadGroupContext();
contexts.put(group, context);
}
return context;
}
} }
private volatile boolean isDesignTime; private volatile boolean isDesignTime;
......
...@@ -33,18 +33,22 @@ import java.lang.ref.WeakReference; ...@@ -33,18 +33,22 @@ import java.lang.ref.WeakReference;
* and reference-equality in place of object-equality to compare them. * and reference-equality in place of object-equality to compare them.
* An entry will automatically be removed when its key is no longer * An entry will automatically be removed when its key is no longer
* in ordinary use. Both null values and the null key are supported. * in ordinary use. Both null values and the null key are supported.
* This class does not require additional synchronization.
* A thread-safety is provided by a fragile combination
* of synchronized blocks and volatile fields.
* Be very careful during editing!
* *
* @see java.util.IdentityHashMap * @see java.util.IdentityHashMap
* @see java.util.WeakHashMap * @see java.util.WeakHashMap
*/ */
final class WeakIdentityMap<T> { abstract class WeakIdentityMap<T> {
private static final int MAXIMUM_CAPACITY = 1 << 30; // it MUST be a power of two private static final int MAXIMUM_CAPACITY = 1 << 30; // it MUST be a power of two
private static final Object NULL = new Object(); // special object for null key private static final Object NULL = new Object(); // special object for null key
private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
private Entry<T>[] table = newTable(1<<3); // table's length MUST be a power of two private volatile Entry<T>[] table = newTable(1<<3); // table's length MUST be a power of two
private int threshold = 6; // the next size value at which to resize private int threshold = 6; // the next size value at which to resize
private int size = 0; // the number of key-value mappings private int size = 0; // the number of key-value mappings
...@@ -54,78 +58,83 @@ final class WeakIdentityMap<T> { ...@@ -54,78 +58,83 @@ final class WeakIdentityMap<T> {
key = NULL; key = NULL;
} }
int hash = key.hashCode(); int hash = key.hashCode();
int index = getIndex(this.table, hash); Entry<T>[] table = this.table;
for (Entry<T> entry = this.table[index]; entry != null; entry = entry.next) { // unsynchronized search improves performance
// the null value does not mean that there are no needed entry
int index = getIndex(table, hash);
for (Entry<T> entry = table[index]; entry != null; entry = entry.next) {
if (entry.isMatched(key, hash)) { if (entry.isMatched(key, hash)) {
return entry.value; return entry.value;
} }
} }
return null; synchronized (NULL) {
} // synchronized search improves stability
// we must create and add new value if there are no needed entry
public T put(Object key, T value) { index = getIndex(this.table, hash);
removeStaleEntries(); for (Entry<T> entry = this.table[index]; entry != null; entry = entry.next) {
if (key == null) { if (entry.isMatched(key, hash)) {
key = NULL; return entry.value;
} }
int hash = key.hashCode();
int index = getIndex(this.table, hash);
for (Entry<T> entry = this.table[index]; entry != null; entry = entry.next) {
if (entry.isMatched(key, hash)) {
T oldValue = entry.value;
entry.value = value;
return oldValue;
}
}
this.table[index] = new Entry<T>(key, hash, value, this.queue, this.table[index]);
if (++this.size >= this.threshold) {
if (this.table.length == MAXIMUM_CAPACITY) {
this.threshold = Integer.MAX_VALUE;
} }
else { T value = create(key);
removeStaleEntries(); this.table[index] = new Entry<T>(key, hash, value, this.queue, this.table[index]);
Entry<T>[] table = newTable(this.table.length * 2); if (++this.size >= this.threshold) {
transfer(this.table, table); if (this.table.length == MAXIMUM_CAPACITY) {
this.threshold = Integer.MAX_VALUE;
// If ignoring null elements and processing ref queue caused massive
// shrinkage, then restore old table. This should be rare, but avoids
// unbounded expansion of garbage-filled tables.
if (this.size >= this.threshold / 2) {
this.table = table;
this.threshold *= 2;
} }
else { else {
transfer(table, this.table); removeStaleEntries();
table = newTable(this.table.length * 2);
transfer(this.table, table);
// If ignoring null elements and processing ref queue caused massive
// shrinkage, then restore old table. This should be rare, but avoids
// unbounded expansion of garbage-filled tables.
if (this.size >= this.threshold / 2) {
this.table = table;
this.threshold *= 2;
}
else {
transfer(table, this.table);
}
} }
} }
return value;
} }
return null;
} }
protected abstract T create(Object key);
private void removeStaleEntries() { private void removeStaleEntries() {
for (Object ref = this.queue.poll(); ref != null; ref = this.queue.poll()) { Object ref = this.queue.poll();
@SuppressWarnings("unchecked") if (ref != null) {
Entry<T> entry = (Entry<T>) ref; synchronized (NULL) {
int index = getIndex(this.table, entry.hash); do {
@SuppressWarnings("unchecked")
Entry<T> prev = this.table[index]; Entry<T> entry = (Entry<T>) ref;
Entry<T> current = prev; int index = getIndex(this.table, entry.hash);
while (current != null) {
Entry<T> next = current.next; Entry<T> prev = this.table[index];
if (current == entry) { Entry<T> current = prev;
if (prev == entry) { while (current != null) {
this.table[index] = next; Entry<T> next = current.next;
if (current == entry) {
if (prev == entry) {
this.table[index] = next;
}
else {
prev.next = next;
}
entry.value = null; // Help GC
entry.next = null; // Help GC
this.size--;
break;
}
prev = current;
current = next;
} }
else { ref = this.queue.poll();
prev.next = next;
}
entry.value = null; // Help GC
entry.next = null; // Help GC
this.size--;
break;
} }
prev = current; while (ref != null);
current = next;
} }
} }
} }
...@@ -164,8 +173,8 @@ final class WeakIdentityMap<T> { ...@@ -164,8 +173,8 @@ final class WeakIdentityMap<T> {
private static class Entry<T> extends WeakReference<Object> { private static class Entry<T> extends WeakReference<Object> {
private final int hash; private final int hash;
private T value; private volatile T value;
private Entry<T> next; private volatile Entry<T> next;
Entry(Object key, int hash, T value, ReferenceQueue<Object> queue, Entry<T> next) { Entry(Object key, int hash, T value, ReferenceQueue<Object> queue, Entry<T> next) {
super(key, queue); super(key, queue);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册