ThreadLocal内存泄漏问题实践(一)

针对

ThreadLocal为什么要设计成private static

深入分析 ThreadLocal 内存泄漏问题

实践ThreadLocal的内存泄漏问题:

 

 

package JVM;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class TestThreadLocal {

private static final int LEN = 10;

public static void main(String[] args) throws InterruptedException {


ExecutorService ex = Executors.newFixedThreadPool(LEN);
TestThread testThread = new TestThread() {
@Override
protected void finalize() throws Throwable {
System.out.println("testThread回收");
}
};

for(int i=0; i<LEN; ++i) {
ex.execute(testThread);
}

TestThread.countDownLatch.await();
System.out.println("任务1完成");

TestThread.threadLocal = null;
System.gc();
System.out.println("第1次gc");

TestThread.threadLocal = new ThreadLocal<TestKey>();
TestThread.countDownLatch = new CountDownLatch(10);
for(int i=0; i<LEN; ++i) {
ex.execute(testThread);
}

TestThread.countDownLatch.await();
System.out.println("任务2完成");

System.gc();
System.out.println("第2次gc");
}

private static class TestKey {
Integer key;

public TestKey(Integer integer) {
key = integer;
}

@Override
public String toString() {
return String.valueOf(key);
}

@Override
protected void finalize() throws Throwable {
System.out.println("回收TestKey:"+key);
}
};

private static class TestThread implements Runnable {

private static AtomicInteger atomicInteger = new AtomicInteger(0);

public static volatile CountDownLatch countDownLatch = new CountDownLatch(10);

public static volatile ThreadLocal<TestKey> threadLocal = new ThreadLocal<TestKey>() {
@Override
protected void finalize() throws Throwable {
System.out.println("回收threadlocal:" + this);
}
};

@Override
public void run() {
TestKey key = new TestKey(atomicInteger.incrementAndGet());

threadLocal.set(key);
System.out.println("线程:"+Thread.currentThread()+":"+ key);
// threadLocal.remove();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();

}
}
}

线程:Thread[pool-1-thread-1,5,main]:1
线程:Thread[pool-1-thread-5,5,main]:2
线程:Thread[pool-1-thread-2,5,main]:3
线程:Thread[pool-1-thread-4,5,main]:4
线程:Thread[pool-1-thread-3,5,main]:5
线程:Thread[pool-1-thread-6,5,main]:6
线程:Thread[pool-1-thread-7,5,main]:7
线程:Thread[pool-1-thread-8,5,main]:8
线程:Thread[pool-1-thread-9,5,main]:9
线程:Thread[pool-1-thread-10,5,main]:10
任务1完成
[GC (System.gc()) [PSYoungGen: 2165K->560K(7168K)] 2165K->568K(100352K), 0.0028411 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 560K->0K(7168K)] [ParOldGen: 8K->434K(93184K)] 568K->434K(100352K), [Metaspace: 3397K->3397K(1056768K)], 0.0131344 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
第1次gc
线程:Thread[pool-1-thread-2,5,main]:11
线程:Thread[pool-1-thread-8,5,main]:13
线程:Thread[pool-1-thread-6,5,main]:12
回收threadlocal:JVM.TestThreadLocal$TestThread$1@554dfb98
线程:Thread[pool-1-thread-7,5,main]:19
线程:Thread[pool-1-thread-5,5,main]:18
线程:Thread[pool-1-thread-4,5,main]:17
线程:Thread[pool-1-thread-3,5,main]:16
线程:Thread[pool-1-thread-10,5,main]:15
线程:Thread[pool-1-thread-9,5,main]:14
线程:Thread[pool-1-thread-1,5,main]:20
任务2完成
[GC (System.gc()) [PSYoungGen: 1229K->128K(7168K)] 1664K->562K(100352K), 0.0006910 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 128K->0K(7168K)] [ParOldGen: 434K->418K(93184K)] 562K->418K(100352K), [Metaspace: 3398K->3398K(1056768K)], 0.0082321 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
第2次gc

 

 

 

没回收,与《多线程实战P154页结果》不一致,不过书上也表明该试验在jdk7下,若在jdk8下进行未必得到同样的结果

 

posted on 2018-07-17 14:32  silyvin  阅读(160)  评论(0编辑  收藏  举报