安全线程利用

时间:2015-09-03 11:25:00

标签: java multithreading memory-leaks executorservice

我正在为这样长时间运行的线程使用单线程执行程序:

executor = Executors.newSingleThreadExecutor(THREAD_FACTORY);
executor.submit(new LongRunnable());

检查要停止的标志:

private class LongRunnable implements Runnable {
        @Override
        public void run() {
            while (isRunning.get()) {
                try {
                    doSomething();
                } catch (InterruptedException e) {
                    ...
                }
            }

        }
    }

并且整个执行都以这种方式中断:

@Override
public void close() throws Exception {
    isRunning.set(false);
    executor.shutdownNow();
}

我仍然可以在分析器中看到一些没有gc-ed的线程(而在日志中,他们正在执行的runnable在循环时退出了最外层)。

问题:确实提供了使用线程策略内存泄漏和线程无泄漏?

2 个答案:

答案 0 :(得分:1)

这是一个使用单线程Executor的示例程序,该程序管理链接线程以便JVM无法关闭,但它只能通过不调用shutdownNow来实现:

import java.util.concurrent.*;

public class Exec {

    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.submit(new MyTask());
        Thread.sleep(20000L);
//        executor.shutdownNow();
        int retryCount = 4;
        while (!executor.isTerminated() && retryCount > 0) {
            System.out.println("waiting for tasks to terminate");
            Thread.sleep(500L);
            retryCount -= 1;
        }       
    }
}

class MyTask implements Runnable {
    public void run() {
        int count = 0;
        try {
            while (!Thread.currentThread().isInterrupted() && count < 10) {
                Thread.sleep(1000L);
                count += 1;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("all done");
    }
}

执行程序使用的线程与任务具有单独的生命周期,此示例显示任务如何完成但线程仍在继续。取消注释shutdownNow会导致执行程序的线程终止。否则主线程会休眠一段时间并退出,导致执行程序的线程挂起,从而阻止JVM退出。

我的猜测是你的close方法没有被调用,你的执行者永远不会被关闭。要获得更多有用的答案,请添加一个MVCE,以便我们可以重现问题。

考虑到中断,不需要保留对Runnable的引用来设置标志。当我读到这个问题时,任务没有完成在这里不是问题,但是让Runnable响应中断并丢失标志仍然会更好,只因为少量事情需要跟踪始终是一种改进。

答案 1 :(得分:1)

我无法看到executorshutDownNow的任何问题。您可能正在查看分析器中的不同线程。

尝试这个类似于你问题中的程序,你可以看到成功关闭后线程不再存在。

public class ExecutorShutdownTest {

private static ExecutorService executor;
private static AtomicLong executorThreadId = new AtomicLong(0);

public static void main(String[] args) {
    // get thread MX bean
    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    // create an executor and start the task
    executor = Executors.newSingleThreadExecutor(new TestThreadFactory());
    LongRunnable runnable = new LongRunnable();
    executor.submit(runnable);
    // main thread: keep running for sometime
    int count = 5;
    while (count-- > 0) {
        try {
            Thread.sleep(1000);
            System.out.println(String.valueOf(threadMXBean.getThreadInfo(executorThreadId.longValue())).replace("\r", "").replace(
                    "\n", ""));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    // main thread: stop the task
    try {
        runnable.close();
        System.out.println(String.valueOf(threadMXBean.getThreadInfo(executorThreadId.longValue())).replace("\r", "").replace("\n", ""));
    } catch (Exception e) {
        e.printStackTrace();
    }
    // main thread: run some more time to verify the executor thread no longer exists
    count = 5;
    while (count-- > 0) {
        try {
            Thread.sleep(1000);
            System.out.println(String.valueOf(threadMXBean.getThreadInfo(executorThreadId.longValue())).replace("\r", "").replace("\n", ""));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private static class LongRunnable implements Runnable {

    private volatile boolean isRunning = true;

    @Override
    public void run() {
        while (isRunning) {
            System.out.println("Running");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        System.out.println("Stopped");
    }

    public void close() throws Exception {
        System.out.println("Stopping");
        isRunning = false;
        executor.shutdownNow();
    }
}

private static class TestThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    TestThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0) {
            @Override protected void finalize() throws Throwable {
                super.finalize();
                // probably bad idea but lets see if it gets here
                System.out.println("Executor thread removed from JVM");
            }
        };
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        executorThreadId.set(t.getId());
        System.out.println("Executor thread created");
        return t;
    }
}

}