Pau*_*nis 259 java multithreading listener
我需要一个解决方案来正确地停止Java中的线程.
我有IndexProcessor实现Runnable接口的类:
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
@Override
public void run() {
boolean run = true;
while (run) {
try {
LOGGER.debug("Sleeping...");
Thread.sleep((long) 15000);
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
run = false;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我有ServletContextListener开始和停止线程的类:
public class SearchEngineContextListener implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);
private Thread thread = null;
@Override
public void contextInitialized(ServletContextEvent event) {
thread = new Thread(new IndexProcessor());
LOGGER.debug("Starting thread: " + thread);
thread.start();
LOGGER.debug("Background process successfully started.");
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOGGER.debug("Stopping thread: " + thread);
if (thread != null) {
thread.interrupt();
LOGGER.debug("Thread successfully stopped.");
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我关闭tomcat时,我在IndexProcessor类中得到了异常:
2012-06-09 17:04:50,671 [Thread-3] ERROR IndexProcessor Exception
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at lt.ccl.searchengine.processor.IndexProcessor.run(IndexProcessor.java:22)
at java.lang.Thread.run(Unknown Source)
Run Code Online (Sandbox Code Playgroud)
我使用的是JDK 1.6.所以问题是:
如何停止线程而不抛出任何异常?
PS我不想使用.stop();方法,因为它已被弃用.
Mat*_*att 288
使用Thread.interrupt()是一种完全可以接受的方式.事实上,如上所述,它可能更适合于旗帜.原因在于,如果您处于可中断的阻塞调用(例如Thread.sleep或使用java.nio Channel操作),您实际上可以立即突破这些调用.
如果使用标志,则必须等待阻止操作完成,然后才能检查标志.在某些情况下,您无论如何都必须这样做,例如使用不可中断的标准InputStream/ OutputStream.
在这种情况下,当线程被中断时,它不会中断IO,但是,您可以在代码中轻松地执行此操作(并且您应该在可以安全停止和清理的关键点处执行此操作)
if (Thread.currentThread().isInterrupted()) {
// cleanup and stop execution
// for example a break in a loop
}
Run Code Online (Sandbox Code Playgroud)
就像我说的那样,主要优点Thread.interrupt()是你可以立即打破可中断的调用,这是你不能用标志方法做的.
DrY*_*Yap 166
在IndexProcessor类中,您需要一种设置标志的方法,该标志通知线程它将需要终止,类似于run您在类范围中使用的变量.
当你想要停止线程时,你设置这个标志并调用join()线程并等待它完成.
通过使用volatile变量或使用与用作标志的变量同步的getter和setter方法,确保该标志是线程安全的.
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private volatile boolean running = true;
public void terminate() {
running = false;
}
@Override
public void run() {
while (running) {
try {
LOGGER.debug("Sleeping...");
Thread.sleep((long) 15000);
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
running = false;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后在SearchEngineContextListener:
public class SearchEngineContextListener implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);
private Thread thread = null;
private IndexProcessor runnable = null;
@Override
public void contextInitialized(ServletContextEvent event) {
runnable = new IndexProcessor();
thread = new Thread(runnable);
LOGGER.debug("Starting thread: " + thread);
thread.start();
LOGGER.debug("Background process successfully started.");
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOGGER.debug("Stopping thread: " + thread);
if (thread != null) {
runnable.terminate();
thread.join();
LOGGER.debug("Thread successfully stopped.");
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 25
简单回答:您可以通过以下两种常见方式之一内部停止线程:
您还可以外部停止线程:
system.exit(这会杀死整个过程)interrupt()方法*kill()或stop())*:期望是这应该停止一个线程.但是,当发生这种情况时,线程实际执行的操作完全取决于开发人员在创建线程实现时所写的内容.
您在run方法实现中看到的常见模式是while(boolean){},其中boolean通常是命名的isRunning,它是其线程类的成员变量,它是易失性的,并且通常可以通过其他类型的setter方法访问,例如kill() { isRunnable=false; }.这些子例程很好,因为它们允许线程在终止之前释放它所拥有的任何资源.
您应该始终通过检查run()循环中的标志(如果有)来结束线程.
你的主题应该是这样的:
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private volatile boolean execute;
@Override
public void run() {
this.execute = true;
while (this.execute) {
try {
LOGGER.debug("Sleeping...");
Thread.sleep((long) 15000);
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
this.execute = false;
}
}
}
public void stopExecuting() {
this.execute = false;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以通过调用结束线程thread.stopExecuting().这样线程就会结束干净,但这需要15秒(由于你的睡眠).你仍然可以调用thread.interrupt(),如果它真的很紧急 - 但首选的方法应该是检查标志.
为避免等待15秒,您可以像这样分开睡眠:
...
try {
LOGGER.debug("Sleeping...");
for (int i = 0; (i < 150) && this.execute; i++) {
Thread.sleep((long) 100);
}
LOGGER.debug("Processing");
} catch (InterruptedException e) {
...
Run Code Online (Sandbox Code Playgroud)
通常,线程在被中断时终止。那么,为什么不使用原生布尔值呢?试试 isInterrupted():
Thread t = new Thread(new Runnable(){
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
// do stuff
}
}});
t.start();
// Sleep a second, and then interrupt
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
t.interrupt();
Run Code Online (Sandbox Code Playgroud)
对于同步我更喜欢使用的CountDownLatch线程,这有助于线程等待直到执行完成的进程.在这种情况下,将CountDownLatch使用具有给定计数的实例设置worker类.到的呼叫await的方法将阻塞,直到当前的计数达到零由于的调用countDown方法或超时集为止.这种方法允许立即中断线程,而不必等待指定的等待时间过去:
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private final CountDownLatch countdownlatch;
public IndexProcessor(CountDownLatch countdownlatch) {
this.countdownlatch = countdownlatch;
}
public void run() {
try {
while (!countdownlatch.await(15000, TimeUnit.MILLISECONDS)) {
LOGGER.debug("Processing...");
}
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
run = false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
当你要完成其他线程的执行,执行进入倒计时CountDownLatch和join线程主线程:
public class SearchEngineContextListener implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);
private Thread thread = null;
private IndexProcessor runnable = null;
private CountDownLatch countdownLatch = null;
@Override
public void contextInitialized(ServletContextEvent event) {
countdownLatch = new CountDownLatch(1);
Thread thread = new Thread(new IndexProcessor(countdownLatch));
LOGGER.debug("Starting thread: " + thread);
thread.start();
LOGGER.debug("Background process successfully started.");
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOGGER.debug("Stopping thread: " + thread);
if (countdownLatch != null)
{
countdownLatch.countDown();
}
if (thread != null) {
try {
thread.join();
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
}
LOGGER.debug("Thread successfully stopped.");
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
540807 次 |
| 最近记录: |