Başlangıç ​​yöntemini aynı iş parçacığında iki kez çağırmak yasal mı?


90

Aşağıdaki kod , programda yöntemi ikinci kezjava.lang.IllegalThreadStateException: Thread already started çağırdığımda yol açar .start()

updateUI.join();    

if (!updateUI.isAlive()) 
    updateUI.start();

Bu ikinci kez updateUI.start()çağrıldığında olur. Birden çok kez adım attım ve iş parçacığı çağrıldı ve vurmadan önce tamamen tamamlandı updateUI.start().

Çağrı updateUI.run(), hatayı önler, ancak iş parçacığının UI iş parçacığında (SO'daki diğer gönderilerde belirtildiği gibi çağıran iş parçacığı) çalışmasına neden olur, bu da istediğim şey değil.

İş Parçacığı yalnızca bir kez başlatılabilir mi? Eğer öyleyse, iş parçacığını yeniden çalıştırmak istersem ne yapmalıyım? Bu özel iş parçacığı arka planda bazı hesaplamalar yapıyor, eğer bunu UI iş parçacığında yapılandan daha iş parçacığında yapmazsam ve kullanıcı mantıksız bir şekilde uzun süre beklemişse.


9
Neden javadoc'u okumadınız - sözleşmeyi açıkça anlatıyor.
mP.

Yanıtlar:


112

Gönderen Java API Şartname için Thread.startyöntemiyle:

Bir ileti dizisini birden fazla başlatmak hiçbir zaman yasal değildir. Özellikle, yürütme tamamlandıktan sonra bir iş parçacığı yeniden başlatılamayabilir.

Ayrıca:

Atar:
IllegalThreadStateException- iş parçacığı zaten başlatılmışsa.

Yani evet, a Threadyalnızca bir kez başlatılabilir.

Eğer öyleyse, iş parçacığını yeniden çalıştırmak istersem ne yapmalıyım?

Eğer bir Threadbirden fazla çalıştırılması gerekiyorsa, o zaman yeni bir örnek oluşturmalı Threadve startonu çağırmalıdır .


Teşekkürler. Belgeleri IDE ve iş parçacıkları için Java öğreticisiyle (ve google da) kontrol ettim. Gelecekte API spesifikasyonunu kontrol edeceğim. Bu kritik "..bir kereden fazla başlamak hiçbir zaman yasal değildir .." diğer okumalarda değildir.
Will

@coobird, eski iş parçacığı nesne adını yeni bir İş parçacığına () atarsam, eski iş parçacığı bittikten sonra, eski iş parçacığı çöp toplanacak mı (yani otomatik olarak geri dönüştürülüyor mu, yoksa bu açıkça yapılmalı mı)?
snapfractalpop

İş Parçacığı artık çalışmadığı sürece çöp toplanacaktır.
2013

1
Bu cevap biraz güncel değil. Modern bir Java programının bir görevi birden fazla kez gerçekleştirmesi gerekiyorsa , Threadher seferinde yeni bir Java oluşturmamalıdır . Bunun yerine, görevi bir iş parçacığı havuzuna (örneğin java.util.concurrent.ThreadPoolExecutor)
Solomon Slow

13

Kesinlikle doğru. Belgelerden :

Bir ileti dizisini birden fazla başlatmak hiçbir zaman yasal değildir. Özellikle, yürütme tamamlandıktan sonra bir iş parçacığı yeniden başlatılamayabilir.

Tekrarlanan hesaplama için yapabilecekleriniz açısından, SwingUtilities invokeLater yöntemini kullanabilirmişsiniz gibi görünüyor . Zaten run()doğrudan arama yapmayı deniyorsunuz , yani zaten Runnableham yerine a kullanmayı düşünüyorsunuz Thread. invokeLaterYöntemi sadece Runnablegörevde kullanmayı deneyin ve bunun zihinsel düzeninize biraz daha iyi uyup uymadığını görün.

İşte belgelerden örnek:

 Runnable doHelloWorld = new Runnable() {
     public void run() {
         // Put your UI update computations in here.
         // BTW - remember to restrict Swing calls to the AWT Event thread.
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };

 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");

Bu printlnaramayı hesaplamanızla değiştirirseniz, tam da ihtiyacınız olan şey olabilir.

DÜZENLEME: yorumu takip ederek, orijinal gönderide Android etiketini fark etmemiştim. Android çalışmasında invokeLater işlevinin eşdeğeri Handler.post(Runnable). Javadoc'undan:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */

Dolayısıyla, Android dünyasında, yukarıdakiyle aynı örneği Swingutilities.invokeLaterkullanarak uygun gönderiyi bir Handler.


OP, SwingUtilities'i içermeyen Android'de iş parçacığı hakkında soru soruyor.
Austyn Mahoney

@Austyn, haklısın. Paralel Android kodunu göstermek için Handler.post () hakkındaki açıklamaları ekledim.
Bob Haç

1
Kullanıcı arayüzünüzü güncellemeye çalışıyorsanız başka bir yol , kendi İşleyicinizi kullanmak RunOnUIThread(Runnable)veya View.post(Runnable)oluşturmak yerine kullanmaktır . Bunlar, kullanıcı arayüzünü güncellemenize izin veren ana iş parçacığı üzerinde çalıştırılabilirliği çalıştıracaktır.
Austyn Mahoney

3

Yeni gelen cevap, yaptığınız şeyi neden yapmamanız gerektiğini kapsar. İşte gerçek probleminizi çözmek için bazı seçenekler.

Bu özel iş parçacığı arka planda bazı hesaplamalar yapıyor, eğer bunu UI iş parçacığında yapılandan daha iş parçacığında yapmazsam ve kullanıcı mantıksız bir şekilde uzun süre beklemişse.

Kendi başlığınızı atın ve kullanın AsyncTask.

Veya ihtiyacınız olduğunda yeni bir iplik oluşturun.

Veya iş parçacığını LinkedBlockingQueueyeniden başlatmak yerine iş parçacığını bir iş kuyruğunda (örneğin ) çalışacak şekilde ayarlayın .


3

Hayır , Thread'ı yeniden başlatamayız, bunu yapmak runtimeException java.lang.IllegalThreadStateException'ı atar. >

Nedeni, run () yöntemi Thread tarafından çalıştırıldığında, ölü duruma geçmesidir.

Bir örnek alalım - Bizim için iş parçacığını yeniden başlatmayı ve üzerinde start () yöntemini çağırmayı düşünmek (ki bu dahili olarak run () yöntemini çağıracak) bizim için ölü adamdan uyanmasını ve koşmasını istemek gibi bir şey. Gibi, hayatını tamamladıktan sonra kişi ölü duruma geçer.

public class MyClass implements Runnable{

    @Override
    public void run() {
           System.out.println("in run() method, method completed.");
    }

    public static void main(String[] args) {
                  MyClass obj=new MyClass();            
        Thread thread1=new Thread(obj,"Thread-1");
        thread1.start();
        thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
    }

}

/ * Run () yönteminde ÇIKIŞ, yöntem tamamlandı. Java.lang.Thread.start adresindeki "main" iş parçacığında istisna java.lang.IllegalThreadStateException (Bilinmeyen Kaynak) * /

şuna göz at


2

Yapmanız gereken, bir Runnable oluşturmak ve Runnable'ı her çalıştırmak istediğinizde yeni bir Thread ile sarmaktır. Bunu yapmak gerçekten çirkin olurdu ama bir iş parçacığını başka bir iş parçacığıyla sarmalayarak kodu tekrar çalıştırabilirsiniz, ancak yalnızca bunu yapın, gerçekten yapmanız gerekir.


herhangi bir snippet, nasıl sarılır?
Vinay

1

Dediğin gibi, bir iş parçacığı birden fazla başlatılamaz.

Doğrudan atın ağzından: Java API Spec

Bir ileti dizisini birden fazla başlatmak hiçbir zaman yasal değildir. Özellikle, yürütme tamamlandıktan sonra bir iş parçacığı yeniden başlatılamayabilir.

Eğer iş parçacığınızda olan her şeyi yeniden çalıştırmanız gerekirse, yeni bir iş parçacığı oluşturmanız ve onu çalıştırmanız gerekecektir.


0

Bir iş parçacığını yeniden kullanmak Java API'de yasa dışı bir eylemdir. Ancak, onu çalıştırılabilir bir uygulamaya sarabilir ve bu örneği yeniden çalıştırabilirsiniz.


0

Evet, zaten iş parçacığı çalıştırmaya başlayamayız. İş parçacığı zaten başlatılmışsa, çalışma zamanında IllegalThreadStateException oluşturur.

İş parçacığını gerçekten başlatmanız gerekiyorsa: Seçenek 1) Bir iş parçacığının birden fazla kez çalıştırılması gerekiyorsa, o zaman yeni bir iş parçacığı örneği oluşturmalı ve onu başlatmalıyız.


0

İş Parçacığı yalnızca bir kez başlatılabilir mi?

Evet. Tam olarak bir kez başlayabilirsiniz.

Eğer öyleyse, iş parçacığını tekrar çalıştırmak istersem ne yapmalıyım? Bu özel iş parçacığı arka planda bazı hesaplamalar yapıyor, eğer bunu iş parçacığında UI iş parçacığında yapıldığından daha yapmazsam ve kullanıcı mantıksız bir şekilde uzun süre beklemek.

Kaçma Threadtekrar. Yerine oluşturmak Runnable ve bunun sonrası Handler ait HandlerThread . Birden fazla Runnablenesne gönderebilirsiniz . Talep senin içinde birlikte UI Konuya veri geri göndermek durumunda Runnable run()yöntemle, bir göndermeden Messageüzerinde HandlerUI Thread ve sürecinhandleMessage

Örnek kod için bu gönderiye bakın:

Android: Bir ileti dizisinde tost


0

Bunun iyi bir uygulama olup olmadığını bilmiyorum ama run () yönteminin run () yöntemi içinde çağrılmasına izin verdiğimde hata yapmıyor ve aslında tam olarak istediğimi yapıyor.

Tekrar iş parçacığı başlatmayacağını biliyorum, ama belki bu sizin için kullanışlı olabilir.

public void run() {

    LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();

    try {
        NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
        Thread.sleep(5000);
        if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
            System.out.println("{There was a NetworkState change!}");
            run();
        } else {
            run();
        }
    } catch (SocketException | InterruptedException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
    checkingNetworkStates.start();
}

Umarım bu biraz da olsa yardımcı olur.

Şerefe


-1

Bunu yapmak gerçekten çirkin olurdu ama bir iş parçacığını başka bir iş parçacığıyla sarmalayarak kodu tekrar çalıştırabilirsiniz, ancak yalnızca bunu yapın, gerçekten yapmanız gerekir.

Bir İş Parçacığı oluşturan bir programcının neden olduğu bir kaynak sızıntısını düzeltmek zorunda kaldım, ancak onu başlatmak () yerine doğrudan run () yöntemini çağırdı. Bu nedenle, hangi yan etkilere neden olduğunu gerçekten bilmiyorsanız, ondan kaçının.


Ancak öneri run()doğrudan çağırmak değil , sadece bir Runnable'ı bir İş Parçacığına yerleştirmek ve muhtemelen çağırmaktı start().
H2ONaCl

@ H2ONaCl Alıntı yaptığım metni okursanız, öneri bir Konuya Bir Konuya sarmaktı. Orijinal öneriyi düzenlenmeden önce okuyamamış olabilirsiniz.
Torben
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.