Android: поток прерываний, содержащийся в методе

В Android Studio у меня есть поток, содержащийся в таком методе (см. Ниже), потому что я хотел бы перезапустить поток всякий раз, когда он называется [1] (воссоздание потока, а не перезапуск)

public void callthread(){ final Thread myThread = new Thread(new Runnable() { @Override public void run() { for (int x=0; x<750&&!Thread.interrupted(); x++) { //using this and thread sleep for repeated timed code within a thread try { Thread.sleep(4); runOnUiThread(new Runnable() { @Override public void run() { //some code if (condition) { myThread.interrupt(); } } }); } catch (InterruptedException e) { } } } }); 

Моя проблема в том, что он не позволит мне использовать myThread.interrupt(); В нужном месте в моем коде, давая мне ошибку, говоря, что «переменная« myThread », возможно, не была инициализирована» и не будет компилироваться из-за этого. Однако он работает, когда весь поток содержится в классе, но у меня нет способа его перезапуска. Другими словами, мне нужен способ прервать поток, пока он содержится в методе. [2]

Принятые решения

[1]. Решение, в котором поток можно перезапустить

[2]. Решение, в котором поток может быть прерван, пока поток содержится в методе

PS: Если это неясно, я редактировал мой код выше для удобства чтения, но я не удалял такие вещи, как цикл for или Thread.sleep поскольку я предполагаю, что они могут быть частью проблемы. Так что если слишком много или слишком мало определенной фигурной скобки, то это не проблема

EDIT: Поиск вокруг и, по-видимому, вы не можете перезапустить нить

Вы можете запустить прерыватель потока в myThread перед вводом for-loop. myThread 5 секунд, а затем прерывает myThread . Прерывание обрабатывается в обработчике исключений. Там переменная x цикла сбрасывается на 0 , что является практически перезапуском цикла.

 public class ThreadInterruptRestart { public static void main(String[] args) { new ThreadInterruptRestart().callthread(); } public void callthread() { final Thread myThread = new Thread("myThread") { @Override public void run() { final Thread _this = this; Thread interruptingThread = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { // this is not the interrupt we are interested in e.printStackTrace(); } if (true) { System.out.println("interrupting " + _this + " from thread " + this); _this.interrupt(); } } }, "interrupting thread"); interruptingThread.start(); for (int x = 0; x < 750; x++) { // using this and thread sleep for repeated timed code // within a thread try { System.out.println(x); Thread.sleep(10); } catch (InterruptedException e1) { // this is the interrupt we want to handle System.out.println("" + this + " interrupted!"); // reset the loop counter x = 0; } } } }; myThread.start(); } } 

И еще одна версия, где myThread не спят, а вместо InterruptedException используется синхронизация:

 public class ThreadInterruptRestart { public static void main(String[] args) { new ThreadInterruptRestart().callthread(); } public void callthread() { final Object mutex = new Object(); final Thread myThread = new Thread("myThread") { @Override public void run() { final Thread _this = this; Thread interruptingThread = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1); } catch (InterruptedException e) { // this is not the interrupt we are interested in e.printStackTrace(); } if (true) { System.out.println("interrupting " + _this + " from thread " + this); synchronized (mutex) { _this.interrupt(); } } } }, "interrupting thread"); interruptingThread.start(); for (int x = 0; x < 75000; x++) { // using this and thread sleep for repeated timed code // within a thread synchronized (mutex) { System.out.println(x); // do other stuff here } if (Thread.interrupted()) { // this is the interrupt we want to handle System.out.println("" + this + " interrupted!"); // reset the loop counter x = 0; } } } }; myThread.start(); } } 

Есть лучшие способы прекратить поток. Однако, если вам нужно получить доступ к потоку, используйте ссылочную переменную следующим образом:

  public void callthread(){ final Thread myThread = new Thread(new Runnable() { @Override public void run() { final Thread _this = this; for (int x=0; x<750&&!Thread.interrupted(); x++) { //using this and thread sleep for repeated timed code within a thread try { Thread.sleep(4); runOnUiThread(new Runnable() { @Override public void run() { //some code if (condition) { _this.interrupt(); } } }); } catch (InterruptedException e) { } } } }); 

Недостатком вашего кода является «Утечка этого конструктора», где вы пытаетесь вызвать метод потока объекта (в вашем случае) до того, как поток был создан.

Чтобы решить эту проблему, вы можете пойти на дизайн, похожий на шаблон Observer

Используется ли это?

Как побочная заметка, runOnUiThread довольно запах кода и может привести к некоторым довольно тонким ошибкам времени. Для чего вы его используете? Также очень сложно сказать, чего вы пытаетесь достичь здесь. Использование чего-то вроде исполнителя может значительно упростить ситуацию.

 public void callthread() { final Thread myThread = new Thread(new Runnable() { @Override public void run() { final Thread thread = Thread.currentThread(); for (int x = 0; x < 750 && !Thread.interrupted(); x++) { //using this and thread sleep for repeated timed code within a thread try { Thread.sleep(4); runOnUiThread(new Runnable() { @Override public void run() { //some code if (true) { thread.interrupt(); } } }); } catch (InterruptedException e) { } } } }); } 

Отчасти проблема заключается в том, что вы теряетесь во вложенных классах задач. Другая часть состоит в том, что вы слишком стараетесь использовать механизм потоковой передачи для выполнения вашего логического контроля. Таким образом, ваши классы контролируют себя и сохраняют простую модель потоков.

ParallelTask

 /** * An implementation of your inner Runnable. */ public class ParallelTask implements Runnable { protected ParallelTaskRunner m_runner = null ; private ParallelTask() {} // Disallow default constructor. public ParallelTask( ParallelTaskRunner runner ) { m_runner = runner ; } @Override public void run() { // The code from that original inner class. if( /* trigger condition */ ) m_runner.stop(this) ; } } 

ParallelTaskRunner

 /** * An implementation of the outer class. */ public class ParallelTaskRunner implements Runnable { public static final int THREAD_COUNT = 750 ; protected boolean m_bRunning = false ; protected ParallelTask m_tskStopper = null ; @Override public void run() { if( m_bRunning ) return ; // Don't run if already running. m_bRunning = true ; m_tskStopper = null ; for( int i = 0 ; i < THREAD_COUNT && m_bRunning ; i++ ) { try { // Insert some wait interval here if desired. (new Thread( new ParallelTask(this) )).run() ; } catch( Exception x ) { Log.w( "ParallelTaskRunner.run()", "Caught exception.", x ) ; } } } public synchronized void stop( ParallelTask tsk ) { m_bRunning = false ; if( m_tskStopper == null ) m_tskStopper = tsk ; } public ParallelTask getStopper() { return m_tskStopper ; } } 

А потом, в каком-то потребительском классе …

 public void callThreads() { ParallelTaskRunner runner = new ParallelTaskRunner() ; (new Thread(runner)).run() ; } 

В callThread() вы можете отображать отчеты на основе данных, содержащихся в runner . Например, если у вас есть потоки, уникально идентифицировать себя с UUID или простым целым числом (индекс цикла?), То ваше приложение может отображать тост с идентификатором задачи «стоппер». Если код, который вы выполняете в ParallelTask выписывает интересные данные, то эти данные могут быть доступны через аксессуар в ParallelTask , который вы вызываете, сначала вызывая runner.getStopper() а затем работая над этим экземпляром ParallelTask .