2013-02-04 2 views
2

부울이 상태를 true로 변경할 때만 계속 스레드에서 실행되는 작업 x가 있습니다. 나는 약간의 독서를했으며, 아래의 코드에있는 쓰레드를 죽일 때 접근하는 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(); 
    } 
} 

}

+1

정말 가장 좋은 방법은 스레드가 무엇을하고 무엇을하고 싶은지를 먼저 코딩하는 것입니다. 그렇게하면 방해하거나 죽일 필요가 없습니다. 자문해야 할 질문은 이것입니다. 왜 내가이 스레드를 코딩하여 내가 원하지 않는 작업을 수행 했습니까? –

+0

어쩌면 내가 문제를 제대로 이해하지 못했을 수도 있습니다. 게시 한 예는 임의의 작업 또는 작업입니다. 내 주요 관심사는 여기에 종료 호출이있는 응용 프로그램이있는 경우 메모리 누수를 피하기 위해 모든 스레드를 깔끔하게 종료하고 싶습니다. 그래서 기본적으로 스레드 종료에 접근하는 가장 좋은 방법을 찾아 내려고했습니다. – kimathie

+0

이해합니다. 유용한 작업이 없을 때 스레드를 종료하도록 코드를 작성하는 것이 좋습니다. 문제는 수행하고 싶지 않은 작업을 수행하도록 코드를 코딩했기 때문입니다. 해결 방법은 해당 스레드에서 코드를 수정하여 수행 할 유용한 작업이 없으면 수행 한 작업 만 수행하고 종료 할 수 있도록하는 것입니다. 인터럽트 또는 종료하도록 "강제"하기 위해 스레드에 "도달"해야한다는 사실은 처음에 잘못 프로그래밍 된 것을 보여줍니다. 실은 전쟁이 아닌 협력해야합니다. –

답변

1

모든 예제에서 스레드를 실제로 죽이지는 않고 더 많은 항목을 처리하지 않도록 배치를 중지하고 있습니다. 차이점을 이해하려면 스레드가 processBatch 함수 내에있는 동안 실제로 스레드를 중지 할 수있는 메소드가 없다는 점에 유의하십시오. 현재 스레드에 인터럽트()를 호출 아무 소용이 없습니다

  • :

    은주의 깊게 살펴 할 몇 가지 사항이 있습니다. 인터럽트의 배경은 외부 스레드가 인터럽트를 호출하는 것입니다. 귀하의 경우에는 예외를 던지거나 run() 함수 (스레드 자동 종료)에서 복귀 할 수 있습니다.

  • 심지어 소켓이 (데이터베이스 연결이 무엇인지)를 포함하여 IO를 기다리는 스레드 (예 : NIO를 사용하지 않는 경우)와 같이 스레드가 Java 외부에서 잠겨있는 경우에도 interrupt() IO 내에서 스레드를 중지하는 다른 방법을 설계해야합니다 (일반적으로 시간 초과를 수행하지만 다른 방법이 있습니다).

당신의 목표는 투입 Joonas에서 코드를 사용 happing에서 다음 배치를 중지하는 것입니다 경우 : 일괄 처리를 실행하는 동안 당신의 목표는 프로세스를 중단하는 경우

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(); 
} 

은 바람직한 방법이며, 로컬 범위 변수 익명 클래스를 사용하는 것은 아주 거친 아이디어 (스레드의 여부를 확인하는 기능과 정적 변수, 또는 그 이상의 삽입 된 인터페이스를 사용할 수있다 hould 계속).

+0

선생님, 나는 이것을 위해 당신을 칭찬해야합니다, 사실 이것은 제가 정확히 찾고 있었던 것입니다. 나는 항상 루프를 멈추게되면 결국 스레드를 죽일 것이라고 생각 해왔다. 나는 항상 스레드를 죽이기를 원했고 그 자체로 인터럽트를 호출했다. 마지막 예제를 사용하여 ServletContextListener를 가정하면 var t를 시작한 var t.interrrupt를 호출하여 실제로 스레드를 종료합니다. – kimathie

+0

t.interrupt()를 호출하면 t 스레드 내부에서 InterruptedException이 발생합니다. T 쓰레드 내에서 예외를 잡을 것이 아무것도 없다면 던져진 예외로 쓰레드가 멈추고 catch 문구가 있으면 (그러면해야 할) 쓰레드가 멈출 것입니다. 실행 함수에서 돌아오고 (따라서 스레드를 죽이기) 또는 다른 것을 결정하십시오. –

6

권장되는 방법은 종료 스레드 루프를 알리기 위해 thread의 인터럽트 플래그를 사용하는 것입니다 : 아래

는 코드입니다. 두 개의 플래그 ( stopped 및 중단 된 플래그)를 사용할 이유가 없으며 중단 된 플래그를 다른 것으로 사용하지 않는 것 같습니다.

보다 광범위한 토론과 예제는 Java 자습서 주제 Interrupts을 참조하십시오.

+0

Ted의 설명에 감사 드리며, 나는이 모든 예들과 정말로 혼동합니다. 나는 Kabutz 살인 실례를 통해 "Batch Worker A"를 사용하고 있었지만 컨셉을 제대로 수행하지 못했던 것 같습니다. – kimathie

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(); 

을하지만 당신은 모든 스레드에 대한 참조를 유지해야하고, 그들 모두를 방해하므로 부울 플래그는 더 간단 할 수 있습니다 (휘발성으로 만들어야 함).

+0

Joonas에게 그들을 단순화시켜 줘서 고마워. – kimathie

관련 문제