Android-스레드를 중지하는 가장 좋고 안전한 방법


79

Android에서 스레드를 중지하는 가장 좋은 방법을 알고 싶습니다. AsyncTask대신 사용할 수 있고 cancel()방법 이 있다는 것을 알고 있습니다 . Thread내 상황에서 s 를 사용해야 합니다. 내가 사용하는 방법은 다음과 같습니다 Thread.

Runnable runnable = new Runnable() {
        @Override
        public void run() {
            //doing some work
        }
    };
new Thread(runnable).start();

그렇다면 스레드를 중지하는 가장 좋은 방법이 무엇인지 아는 사람이 있습니까?

답변:


90

스레드 지원 인터럽트를 만들어야합니다. 기본적으로 yourThread.interrupt()스레드를 중지하기 위해 호출 할 수 있으며 run () 메서드에서 주기적으로 상태를 확인해야합니다.Thread.interrupted()

여기에 좋은 튜토리얼이 있습니다 .


감사합니다. 저는 항상 cancel () 또는 stop ()을 찾고있었습니다.
Miloš Černilovský

@ MilošČernilovský stop()메서드는 더 이상 사용되지 않으며 더 이상 사용하지 않아야합니다.
Alston 19

29

이 상황은 표준 Java와 전혀 다르지 않습니다. 표준 방법을 사용하여 스레드를 중지 할 수 있습니다.

class WorkerThread extends Thread {
    volatile boolean running = true;

    public void run() {
        // Do work...
        if (!running) return;
        //Continue doing the work
    }
}

주요 아이디어는 수시로 필드의 가치를 확인하는 것입니다. 스레드를 중지해야하는 경우 runningfalse로 설정 합니다. 또한 Chris가 지적했듯이 중단 메커니즘을 사용할 수 있습니다.

그건 그렇고, AsyncTask를 사용할 때 접근 방식은 크게 다르지 않습니다. 유일한 차이점은 isCancel()특수 필드를 갖는 대신 작업에서 메서드 를 호출해야한다는 것입니다 . 를 호출 cancel(true)하지만이 메커니즘을 구현하지 않으면 스레드가 여전히 저절로 중지되지 않고 끝까지 실행됩니다.


23

Android에서는 일반 Java 환경과 동일한 규칙이 적용됩니다. Java에서 스레드는 종료되지 않지만 스레드 중지는 협력적인 방식으로 수행됩니다 . 스레드는 종료하도록 요청되고 스레드는 정상적으로 종료 될 수 있습니다.

종종 volatile boolean스레드가 해당 값으로 설정 될 때 주기적으로 확인하고 종료 하는 필드가 사용됩니다.

나는 스레드가 종료 되어야하는지 여부를 확인 하기 위해 사용 하지 않을 것 입니다. 필드 수정 자로 사용하면 안정적으로 작동하지만 코드가 더 복잡해지면 루프 내에서 다른 차단 방법을 대신 사용 하기 때문에 코드가 전혀 종료되지 않거나 최소한 시간이 더 오래 걸릴 수 있습니다. 아마도 원한다.booleanvolatilewhile

특정 차단 라이브러리 방법은 중단을 지원합니다.

모든 스레드에는 이미 부울 플래그 인터럽트 상태 가 있으므로 이를 사용해야합니다. 다음과 같이 구현할 수 있습니다.

public void run() {

   try {
      while(!Thread.currentThread().isInterrupted()) {
         // ...
      }
   } catch (InterruptedException consumed)
      /* Allow thread to exit */
   }

}

public void cancel() { interrupt(); }

Java Concurrency in Practice 에서 가져온 소스 코드 입니다. cancel()메서드가 공용 이므로 원하는대로 다른 스레드가이 메서드를 호출하도록 할 수 있습니다.

interrupted현재 스레드의 중단 된 상태를 지우는 이름 이 잘못된 정적 메서드도 있습니다 .


2
Android Studio에서는 해당 try 블록에서 예외 'java.lang.InterruptedException'이 발생하지 않습니다.
CraPo

1
@CraPo while 루프 앞에 이것을 추가하십시오.if (Thread.interrupted()) { throw new InterruptedException();}
Kosso

16

Thread.stop()스레드를 중지하는 데 사용 될 수있는 방법은 사용되지 않습니다; 자세한 내용은 다음을 참조하십시오. Thread.stop, Thread.suspend 및 Thread.resume이 더 이상 사용되지 않는 이유는 무엇입니까? .

가장 좋은 방법은 스레드 자체가 참조하는 변수를 가지고 변수가 특정 값과 같으면 자발적으로 종료하는 것입니다. 그런 다음 스레드가 종료되기를 원할 때 코드 내에서 변수를 조작합니다. 물론 AsyncTask대신 사용할 수도 있습니다 .


4
AsyncTask는 실제로 중단 메커니즘의 대안이 아니며 UI와 상호 작용하는 도구입니다. 내 대답에서 지적했듯이 실행 중에 중지 할 수 있으려면 일반 스레드에서와 마찬가지로 AsyncTask에서 동일한 메커니즘을 구현해야합니다.
Malcolm

2

현재 그리고 안타깝게도 스레드를 중지하기 위해 아무것도 할 수 없습니다 ....

Matt의 대답에 무언가를 추가하면 우리가 호출 할 수는 interrupt()있지만 스레드를 중지하지는 않습니다. 시스템이 스레드를 중지하려고 할 때 시스템에 스레드를 중지하도록 지시합니다. 휴식은 시스템에 의해 이루어지며을 호출하여 확인할 수 있습니다 interrupted().

[ps : 정말 같이 가신다면 interrupt()전화를 걸어 잠깐자는 실험을 해보 시죠 interrupt()]


2

이렇게 해봐

Thread thread = new Thread() {
    @Override
    public void run() {
        Looper.prepare();   
        while(true){ 
            Log.d("Current Thread", "Running"); 
            try{
               Thread.sleep(1000);
            }catch(Exeption exception){ }
        }
    }
};

thread.start();
thread.interrupt();

1

스레드를 중지하는 데 선호되는 두 가지 방법이 있습니다.

  1. 휘발성 부울 변수를 만들고 그 값을 false로 변경하고 스레드 내부를 확인합니다.

    volatile isRunning = false;
    
    public void run() {
    if(!isRunning) {return;}       
    
    }
    
  2. 또는 스레드 내부에서받을 수있는 interrupt () 메서드를 사용할 수 있습니다.

    SomeThread.interrupt();
    
    public void run() {
    if(Thread.currentThread.isInterrupted()) {return;}
     }
    

0

이 방법을 사용했습니다.

Looper.myLooper().quit();

당신은 시도 할 수 있습니다.


0

이것은 나를 위해 이렇게 작동했습니다. 주요 활동에 정적 변수를 도입하고 아래에서 어떻게했는지 정기적으로 확인하십시오.

public class MainActivity extends AppCompatActivity {


//This is the static variable introduced in main activity
public static boolean stopThread =false;



  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Thread thread = new Thread(new Thread1());
    thread.start();

    Button stp_thread= findViewById(R.id.button_stop);

    stp_thread.setOnClickListener(new Button.OnClickListener(){
           @Override
           public void onClick(View v){
              stopThread = true;
           }

     }

  }


  class Thread1 implements Runnable{

        public void run() {

        // YOU CAN DO IT ON BELOW WAY 
        while(!MainActivity.stopThread) {
             Do Something here
        }


        //OR YOU CAN CALL RETURN AFTER EVERY LINE LIKE BELOW

        process 1 goes here;

        //Below method also could be used
        if(stopThread==true){
            return ;
        }
        // use this after every line



        process 2 goes here;


        //Below method also could be used
        if(stopThread==true){
            return ;
        }
        // use this after every line


        process 3 goes here;


        //Below method also could be used
        if(stopThread==true){
            return ;
        }
        // use this after every line


        process 4 goes here;



       }
   }

}

0

프로젝트에 핸들러가있는 스레드 클래스가있는 경우 여기에서 중지하려는 경우 프래그먼트 클래스 중 하나에서 시작했을 때 프래그먼트가 스택에서 제거 될 때 앱을 중지하고 충돌을 방지하는 방법이 있습니다.

이 코드는 Kotlin에 있습니다. 완벽하게 작동합니다.

class NewsFragment : Fragment() {

    private var mGetRSSFeedsThread: GetRSSFeedsThread? = null

    private val mHandler = object : Handler() {

        override fun handleMessage(msg: Message?) {


            if (msg?.what == GetRSSFeedsThread.GETRSSFEEDSTHREAD_SUCCESS) {
                val updateXMLdata = msg.obj as String
                if (!updateXMLdata.isNullOrEmpty())
                    parseUpdatePager(CommonUtils.getJSONObjectFromXML(updateXMLdata).toString())

            } else if (msg?.what == GetRSSFeedsThread.GETRSSFEEDSTHREAD_SUCCESS) {
                BaseActivity.make_toast(activity, resources.getString(R.string.pleaseTryAgain))
            }

        }
    }
    private var rootview: View? = null;
    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        rootview = inflater?.inflate(R.layout.fragment_news, container, false);

        news_listView = rootview?.findViewById(R.id.news_listView)
        mGetRSSFeedsThread = GetRSSFeedsThread(this.activity, mHandler)


        if (CommonUtils.isInternetAvailable(activity)) {
            mGetRSSFeedsThread?.start()
        }


        return rootview
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true);

    }



    override fun onAttach(context: Context?) {
        super.onAttach(context)
        println("onAttach")
    }

    override fun onPause() {
        super.onPause()
        println("onPause fragment may return to active state again")

        Thread.interrupted()

    }

    override fun onStart() {
        super.onStart()
        println("onStart")

    }

    override fun onResume() {
        super.onResume()
        println("onResume fragment may return to active state again")

    }

    override fun onDetach() {
        super.onDetach()
        println("onDetach fragment never return to active state again")

    }

    override fun onDestroy() {
        super.onDestroy()

        println("onDestroy fragment never return to active state again")
       //check the state of the task
        if (mGetRSSFeedsThread != null && mGetRSSFeedsThread?.isAlive!!) {
            mGetRSSFeedsThread?.interrupt();
        } else {

        }

    }

    override fun onDestroyView() {
        super.onDestroyView()
        println("onDestroyView fragment may return to active state again")



    }

    override fun onStop() {
        super.onStop()
        println("onStop fragment may return to active state again")



    }
}

위의 코드는 현재 조각에서 다른 조각 또는 활동으로 전환 할 때 실행중인 스레드를 중지합니다. 또한 현재 조각으로 돌아갈 때 다시 생성됩니다.


0

문제는 스레드가 실행 중인지 여부를 확인해야한다는 것입니다 !?

들:

private boolean runningThread = false;

스레드에서 :

new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep((long) Math.floor(speed));
                        if (!runningThread) {
                            return;
                        }
                        yourWork();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

스레드를 중지하려면 아래 필드를 만들어야합니다.

private boolean runningThread = false;

2
이것은를 중지하지 않고 호출 Thread만 중지 yourWork();합니다. 이를 테스트하려면 당신은 추가 할 수 있습니다 Log아래public void run() {
KRK

@KRK 나는 이것을 알고있다! 그리고 나는 스레드에 아무것도하지 않고 무언가를 멈추고 다시 시작하고 싶을 때 매우 유용하기 때문에이 답변을 게시했습니다.
Hadi Note

@HadiNote KRK가 정확합니다. 당신은 당신의 대답에 진술합니다 If you want to stop the thread you should make the below field: private boolean runningThread = false;. 이것은 올바르지 않습니다.
pookie

0

내 요구 사항은 질문과 약간 달랐지만 스레드가 작업을 실행하는 것을 중지하는 유용한 방법이기도합니다. 내가 원하는 것은 화면을 종료 할 때 스레드를 중지하고 화면으로 돌아가는 동안 다시 시작하는 것입니다.

Android 문서에 따라 이것은 API 15에서 더 이상 사용되지 않는 중지 메서드 의 제안 된 대체입니다.

stop의 많은 사용은 대상 스레드가 실행을 중지해야 함을 나타 내기 위해 일부 변수를 수정하는 코드로 대체되어야합니다. 대상 스레드는이 변수를 정기적으로 확인하고, 변수가 실행을 중지 할 것임을 나타내는 경우 순서대로 실행 메서드에서 반환해야합니다.

내 스레드 클래스

   class ThreadClass implements Runnable {
            ...
                  @Override
                        public void run() {
                            while (count < name.length()) {

                                if (!exited) // checks boolean  
                                  {
                                   // perform your task
                                                     }
            ...

OnStop 및 OnResume은 다음과 같습니다.

  @Override
    protected void onStop() {
        super.onStop();
        exited = true;
    }

    @Override
    protected void onResume() {
        super.onResume();
        exited = false;
    }

0

Thread.stop ()이 JAVA에서 더 이상 사용되지 않는다는 것을 알고 있듯이 Thread.stop은 스레드에서 interrupt () 메서드를 호출하여 스레드를 중지합니다. Interrupt는 스레드가 대기하도록 유지하는 메서드에서 throw됩니다. 실행이 완료된 후 알릴 다른 스레드. 이 스레드의 실행으로 처리되지 않는 경우 인터럽트 스레드에 아무것도를 일으킬 것 같은, if(Thread.interrupted())return; 그래서 우리는 기본적으로 호출하는 것처럼 스레드의 시작과 정지를 관리 할 필요가 전부 start()같은 방법을 Thread.start()시작을 while(true)내부 run()의 방법 스레드를 수행하고 각 반복에서 인터럽트 된 상태를 확인하고 스레드에서 반환합니다.

다음과 같은 상황에서는 스레드가 죽지 않습니다.

  1. 스레드가 아직 run ()에서 반환되지 않았습니다.
  2. 스레드가 소유 한 모든 개체에 액세스 할 수 있습니다. (이것은 나머지를 수행하기 위해 GC에 대한 참조를 null / 삭제하라는 힌트)

-2

모든 Activity 클래스 내에서 스레드 실행을 중지하기 위해 depreciated stop () 메서드의 대안으로 사용할 수있는 스레드 인스턴스에 NULL을 할당하는 메서드를 만듭니다.

public class MyActivity extends Activity {

private Thread mThread;  

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);


        mThread =  new Thread(){
        @Override
        public void run(){
            // Perform thread commands...
    for (int i=0; i < 5000; i++)
    {
      // do something...
    }

    // Call the stopThread() method.
            stopThread(this);
          }
        };

    // Start the thread.
        mThread.start(); 
}

private synchronized void stopThread(Thread theThread)
{
    if (theThread != null)
    {
        theThread = null;
    }
}
}

이것은 문제없이 나를 위해 작동합니다.


11
Thread변수를로 설정 null하면 스레드가 중지되지 않습니다. 논쟁을 null내부로 설정하는 stopThread것은 완전한 시간 낭비입니다.
Ted Hopp

2
이것이 스레드를 어떻게 멈출 수 있습니까? 왜 이것에 대해 긍정적 인 투표가 있는가?
mvd

1
이것은 스레드를 중지하지 않습니다. 스레드는 여전히 실행 중이고 이것은 스레드의 인스턴스에 null을 할당하여 해당 스레드를 제어 할 수 없도록합니다. 인스턴스를 잃었 기 때문입니다 (프로세스가 끝날 때까지 계속 실행 됨)
Teocci
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.