All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.portal.kernel.util.ClearThreadLocalUtil Maven / Gradle / Ivy

There is a newer version: 7.4.3.112-ga112
Show newest version
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.portal.kernel.util;

import com.liferay.petra.reflect.ReflectionUtil;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;

import java.lang.ref.Reference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author Tina Tian
 */
public class ClearThreadLocalUtil {

	public static void clearThreadLocal() throws Exception {
		if (!_INITIALIZED) {
			return;
		}

		Thread[] threads = ThreadUtil.getThreads();

		Thread currentThread = Thread.currentThread();

		ClassLoader contextClassLoader = currentThread.getContextClassLoader();

		for (Thread thread : threads) {
			_clearThreadLocal(thread, contextClassLoader);
		}
	}

	private static void _clearThreadLocal(
			Thread thread, ClassLoader classLoader)
		throws Exception {

		if (thread == null) {
			return;
		}

		Object threadLocalMap = _threadLocalsField.get(thread);

		Object inheritableThreadLocalMap = _inheritableThreadLocalsField.get(
			thread);

		_clearThreadLocalMap(threadLocalMap, classLoader);
		_clearThreadLocalMap(inheritableThreadLocalMap, classLoader);
	}

	private static void _clearThreadLocalMap(
			Object threadLocalMap, ClassLoader classLoader)
		throws Exception {

		if (threadLocalMap == null) {
			return;
		}

		Object[] table = (Object[])_tableField.get(threadLocalMap);

		if (table == null) {
			return;
		}

		int staleEntriesCount = 0;

		for (Object tableEntry : table) {
			if (tableEntry == null) {
				continue;
			}

			Object key = ((Reference)tableEntry).get();
			Object value = _valueField.get(tableEntry);

			boolean remove = false;

			if (key != null) {
				Class keyClass = key.getClass();

				ClassLoader keyClassLoader = keyClass.getClassLoader();

				if (keyClassLoader == classLoader) {
					remove = true;
				}
			}

			if (value != null) {
				Class valueClass = value.getClass();

				ClassLoader valueClassLoader = valueClass.getClassLoader();

				if (valueClassLoader == classLoader) {
					remove = true;
				}
			}

			if (remove) {
				if (key != null) {
					if (_log.isDebugEnabled()) {
						Class keyClass = key.getClass();

						_log.debug(
							"Clear a ThreadLocal with key of type " +
								keyClass.getCanonicalName());
					}

					_removeMethod.invoke(threadLocalMap, key);
				}
				else {
					staleEntriesCount++;
				}
			}
		}

		if (staleEntriesCount > 0) {
			_expungeStaleEntriesMethod.invoke(threadLocalMap);
		}
	}

	private static final boolean _INITIALIZED;

	private static final Log _log = LogFactoryUtil.getLog(
		ClearThreadLocalUtil.class);

	private static final Method _expungeStaleEntriesMethod;
	private static final Field _inheritableThreadLocalsField;
	private static final Method _removeMethod;
	private static final Field _tableField;
	private static final Field _threadLocalsField;
	private static final Field _valueField;

	static {
		boolean initialized = false;

		Method expungeStaleEntriesMethod = null;
		Field inheritableThreadLocalsField = null;
		Method removeMethod = null;
		Field tableField = null;
		Field threadLocalsField = null;
		Field valueField = null;

		try {
			inheritableThreadLocalsField = ReflectionUtil.getDeclaredField(
				Thread.class, "inheritableThreadLocals");
			threadLocalsField = ReflectionUtil.getDeclaredField(
				Thread.class, "threadLocals");

			Class threadLocalMapClass = Class.forName(
				"java.lang.ThreadLocal$ThreadLocalMap");

			expungeStaleEntriesMethod = ReflectionUtil.getDeclaredMethod(
				threadLocalMapClass, "expungeStaleEntries");
			removeMethod = ReflectionUtil.getDeclaredMethod(
				threadLocalMapClass, "remove", ThreadLocal.class);
			tableField = ReflectionUtil.getDeclaredField(
				threadLocalMapClass, "table");

			Class threadLocalMapEntryClass = Class.forName(
				"java.lang.ThreadLocal$ThreadLocalMap$Entry");

			valueField = ReflectionUtil.getDeclaredField(
				threadLocalMapEntryClass, "value");

			initialized = true;
		}
		catch (Throwable t) {
			if (_log.isWarnEnabled()) {
				_log.warn("Failed to initialize ClearThreadLocalUtil", t);
			}
		}

		_expungeStaleEntriesMethod = expungeStaleEntriesMethod;
		_inheritableThreadLocalsField = inheritableThreadLocalsField;
		_removeMethod = removeMethod;
		_tableField = tableField;
		_threadLocalsField = threadLocalsField;
		_valueField = valueField;

		_INITIALIZED = initialized;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy