ThreadLocal
утечка памяти
Основной причиной утечки памяти ThreadLocal является дизайн Entry в его внутреннем классе ThreadLocalMap. Entry наследует WeakReference
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
...
}
Как решить эту проблему с утечкой памяти
Каждый раз, когда используется ThreadLocal, вызывается его метод remove() для очистки данных.
Как разработчики JDK избегают утечек памяти
В методе get(), предоставленном ThreadLocal, вызывается метод ThreadLocalMap#getEntry() для проверки ключа и удаления нулевого ключа.
private Entry getEntry(ThreadLocal<?> key) {
// 拿到索引位置
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
Если ключ равен нулю, будет вызван метод getEntryAfterMiss(), в этом методе, если k == null, будет вызван метод expungeStaleEntry(i);
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal<?> k = e.get();
if (k == key)
return e;
if (k == null)
expungeStaleEntry(i);
else
i = nextIndex(i, len);
e = tab[i];
}
return null;
}
Метод expungeStaleEntry(i) завершает присвоение значения, соответствующего ключу с ключом=null, освобождая место во избежание утечек памяти.
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
// expunge entry at staleSlot
tab[staleSlot].value = null;
tab[staleSlot] = null;
size--;
// Rehash until we encounter null
Entry e;
int i;
// 遍历下一个key为空的entry, 并将value指向null
for (i = nextIndex(staleSlot, len);
(e = tab[i]) != null;
i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
if (k == null) {
e.value = null;
tab[i] = null;
size--;
} else {
int h = k.threadLocalHashCode & (len - 1);
if (h != i) {
tab[i] = null;
// Unlike Knuth 6.4 Algorithm R, we must scan until
// null because multiple entries could have been stale.
while (tab[h] != null)
h = nextIndex(h, len);
tab[h] = e;
}
}
}
return i;
}
Точно так же метод set() наконец вызывает этот метод (expungeStaleEntry), путь вызова: set(T value)->map.set(this, value)->rehash()->expungeStaleEntries()
метод удаления remove()->ThreadLocalMap.remove(this)->expungeStaleEntry(i)
При этом можно лишь сказать, что утечки памяти максимально избегаются, но полностью проблему утечек памяти это не решит. Например, в крайних случаях мы только создаем ThreadLocal, но не вызываем методы set, get, remove и т. д. Таким образом, лучший способ решить проблему — вручную вызвать remove() после использования ThreadLocal.
Ручное удаление? Как вы собираетесь разрабатывать/внедрять?
Если это проект Spring, его можно вызвать на этапе afterCompletion перехватчика с помощью цикла объявления bean-компонента.
Слабые ссылки вызывают утечку памяти, так почему ключ не установлен на сильную ссылку
Если для ключа задана сильная ссылка, при освобождении экземпляра threadLocal threadLocal=null, но threadLocal будет иметь сильную ссылку на threadLocalMap, а threadLocalMap.Entry будет строго ссылаться на threadLocal, из-за чего threadLocal не будет нормально перерабатываться ГК.
Хотя слабые ссылки могут вызвать утечку памяти, существуют также средства для удаления нулевых ключей с помощью методов set, get и remove, которые несколько лучше.
Будет ли значение очищено после завершения выполнения потока?
На самом деле, когда выполнение currentThread завершается, threadLocalMap становится недостижимым и перерабатывается, а Entry и т. д. также перерабатываются, но эта среда требует, чтобы Threads не использовались повторно, но потоки часто повторно используются в нашем проекте для повышения производительности. поэтому currentThread обычно не находится в состоянии завершения.
Какова связь между Thread и ThreadLocal?
Thread и ThreadLocal связаны, ThreadLocal полагается на Thread для выполнения, а Thread хранит данные, которые необходимо изолировать в ThreadLocal (точнее, в ThreadLocalMap) для реализации многопоточной обработки.
Связанное расширение вопроса
Как Spring справляется с проблемами параллелизма при многопоточности bean-компонентов
ThreadLocal создан для решения проблемы конфликта доступа к одной и той же переменной, поэтому этот многопоточный доступ к одноэлементному компоненту Spring по умолчанию является идеальным решением. Spring использует ThreadLocal для решения проблемы безопасности потоков, связанной с параллелизмом одной и той же переменной в нескольких потоках.
Как Spring гарантирует, что транзакции базы данных выполняются под одним и тем же соединением
Чтобы реализовать транзакцию jdbc, она должна работать в одном и том же объекте подключения, а транзакции при нескольких подключениях будут неконтролируемыми и должны выполняться с помощью распределенных транзакций. Как Spring гарантирует, что транзакции базы данных выполняются под одним и тем же соединением?
DataSourceTransactionManager — это менеджер транзакций источника данных Spring.Он получит соединение из пула соединений с базой данных, когда вы вызовете getConnection(), затем привяжет его к ThreadLocal и отсоединит его после завершения транзакции. Это гарантирует, что транзакция будет завершена под тем же соединением.
Подробный исходный код:
- Фаза начала транзакции: org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin->TransactionSynchronizationManager#bindResource->org.springframework.transaction.support.TransactionSynchronizationManager#bindResource
-
Конечная фаза транзакции:
org.springframework.jdbc.datasource.DataSourceTransactionManager#doCleanupAfterCompletion->TransactionSynchronizationManager#unbindResource->org.springframework.transaction.support.TransactionSynchronizationManager#unbindResource->TransactionSynchronizationManager#doUnbindResource
Если вам нравятся мои статьи, обратите внимание на мой публичный аккаунт, который пока находится на начальной стадии, спасибо за вашу поддержку.
Обратите внимание на публичный номер, ответьтеjava架构
Получите архитектурные видеоресурсы (другие высококачественные ресурсы будут опубликованы позже). Отвечать找对象
Я могу втянуть тебя в группу знакомств IT-одиночек.
Чтобы просмотреть прошлые статьи, нажмите на мой адрес GitHub:GitHub.com/Антикоррупционное бюро 2016/ Просто…