这是杀死线程的最佳和/或最有效的方法

时间:2013-02-04 09:16:17

标签: java multithreading concurrency thread-safety

我有一个任务x,它在一个线程中连续执行,只有在布尔值将其状态变为true时才会停止。我已经做了一些阅读,在杀死下面代码中的线程时,我有3种方法。 3种方法中哪一种有效?如果它们都没有效果或正确,请提供适当的方法,并提供一些代码供参考。

以下是代码:

public class MyTest {

private static class transaction {

     private String param1,param2,param3, param4, param5;

     public transaction (String param1,String param2,String param3,String param4,String param5){
         this.param1=param1;
         this.param2=param2;
         this.param3=param3;
         this.param4=param4;
         this.param5=param5;
     }

     public String getParam1(){
         return this.param1;
     }

     public String getParam2(){
         return this.param2;
     }

     public String getParam3(){
         return this.param3;
     }

     public String getParam4(){
         return this.param4;
     }

     public String getParam5(){
         return this.param5;
     }
}

public static void processBatch(String workerName){

    try{

        java.util.List <transaction> transactions= new java.util.LinkedList<transaction>();
        java.sql.ResultSet dbtrx=Database.db.execQuery((Object)"dbname.procname");

        while(dbtrx.next()){// Takes a snapshot of the pending payments in the table and stores it into the list.
            Object obj=new transaction (dbtrx.getString("col1"), dbtrx.getString("col2"), dbtrx.getString("col3"), dbtrx.getString("col4"), dbtrx.getString("col5"));
            transactions.add((transaction)obj);
            obj=null;
        }

        java.util.Iterator<transaction> iterate= transactions.iterator();

        /* Processes the pending batch payments*/
        while(iterate.hasNext()){
            transaction trx=iterate.next();
            /*Calls posting function here*/
            System.out.println(workerName+":- Param1 : "+trx.getParam1()+" - Param2 : " +trx.getParam2()+
                    " - Param3 : "+ trx.getParam3()+" - Param4 : "+ trx.getParam4()+" - Param5 : "+ trx.getParam5());
            iterate.remove();
        }

        /*cleaning object references*/
        dbtrx=null;
        transactions=null;
        iterate=null;

     }catch(Exception e){
        e.printStackTrace();
     }
}

public static void main(String [] args) throws InterruptedException{
    volatile boolean stop=false;
    Object hold= new Object();
    new Thread("Batch Worker A"){
        @Override 
        public void run(){
            while(true){
                if(stop!=true){
                    processBatch(Thread.currentThread().getName());
                }else{
                    try{
                    Thread.sleep(0);
                    Thread.currentThread().interrupt();
                    }catch(java.lang.InterruptedException e){
                        Thread.currentThread().interrupt(); 
                        break;
                    }
                }
            }
        }}.start();

    new Thread("Batch Worker B"){
        @Override 
        public void run(){
            try{
                while(stop!=true){
                    processBatch(Thread.currentThread().getName());
                }
                Thread.sleep(0);
                Thread.currentThread().interrupt();
            }catch(java.lang.InterruptedException e){
                Thread.currentThread().interrupt(); 
            }
        }}.start();

    new Thread("Batch Worker C"){
        @Override 
        public void run(){
            while(!Thread.currentThread().isInterrupted()){
                if(stop!=true){
                    processBatch(Thread.currentThread().getName());
                }else{
                    Thread.currentThread().interrupt();
                }
            }
        }}.start();
    }
}

}

3 个答案:

答案 0 :(得分:6)

推荐的方法是使用线程的中断标志来通知线程循环终止。没有理由使用两个标志(stopped和中断的标志),而且你似乎没有使用被打断的标志。

有关更广泛的讨论和示例,请参阅Java教程主题Interrupts

答案 1 :(得分:3)

为什么不这么简单:

new Thread("Batch Worker A"){
    @Override 
    public void run() {
        while(!stop){
                processBatch(Thread.currentThread().getName());
            }
        }
    }}.start();

或者,像这样使用Thread.interrupt()

new Thread("Batch Worker A"){
    @Override 
    public void run() {
        while(!interrupted()){
                processBatch(Thread.currentThread().getName());
            }
        }
    }}.start();

但是你需要保持对所有线程的引用,并将它们全部中断,所以boolean标志可能更简单(确保它变得不稳定)。

答案 2 :(得分:1)

在所有示例中,您并没有真正杀死该线程,您正在停止批处理以处理更多项目。 要理解这些差异,请注意,当线程在processBatch函数中时,您的方法都不会实际停止线程。

有些事情需要注意:

  • 在当前线程上调用Interrupt()没有意义。 Interrupt背后的想法是让外部线程调用它。在你的情况下,你也可以抛出异常,或者从run()函数返回(这将自动关闭线程)。
  • 即使是中断()也不能在很多情况下停止线程,如果该线程被锁定在java之外,如线程等待IO(如果不使用NIO),包括套接字,这就是数据库连接,你我需要设计一种不同的方法来阻止IO内部的线程(通常是通过执行超时,但还有其他方法)。

如果您的目标仅仅是停止下一批处理,请使用Joonas中的代码:

new Thread("Batch Worker A"){
@Override 
public void run() {
    while(!stop){
            processBatch(Thread.currentThread().getName());
        }
    }
}}.start();

如果您的目标是在运行批处理时中断该过程,您也可以这样做:

public static void main(String[] args) {
   var t =new Thread("Batch Worker A"){
      @Override 
      public void run() {
         processBatch(Thread.currentThread().getName());
       }
   }.start(); 
   t.interrupt();
}

一般来说,中断是首选方法,并且使用本地范围的变量和匿名类是一个非常糟糕的主意(使用静态变量,或者更好的注入接口与函数来检查线程是否应该继续)。