簡體   English   中英

Java多線程-運行線程僅按順序運行一次方法

[英]Java multi threading - run threads run method only once in sequence

在我的應用程序中,整個程序的整個生命周期內必須執行n個動作,一個接一個地執行。 我決定不創建實現這些動作的方法並在while(true)循環中依次調用它們,而是決定為每個動作創建一個線程,並使它們執行一次run方法,然后等待所有其他線程完成操作。同樣,等待輪到它,然后重新執行,依此類推...

為了實現此機制,我創建了一個名為StatusHolder的類,該類具有一個名為threadTurn的字段(表示應執行哪個線程),一種讀取該值的方法以及一個用於更新該值的方法。 (請注意,此類使用Singleton設計模式)

package Test;

public class StatusHolder
{
    private static volatile StatusHolder statusHolderInstance = null;
    public static volatile int threadTurn = 0;

    public synchronized static int getTurn()
    {
        return threadTurn;
    }

    public synchronized static void nextTurn()
    {
        System.out.print("Thread turn: " + threadTurn + " --> ");

        if (threadTurn == 1)
        {
            threadTurn = 0;
        }
        else
        {
            threadTurn++;
        }

        System.out.println(threadTurn);

        //Wake up all Threads waiting on this obj for the right turn to come
        synchronized (getStatusHolder())
        {
            getStatusHolder().notifyAll();
        }
    }

    public static synchronized StatusHolder getStatusHolder()
    {//Returns reference to this object

        if (statusHolderInstance == null)
        {
            statusHolderInstance = new StatusHolder();
        }

        return statusHolderInstance;
    }
}

然后,我有兩個必須以上述方式執行的線程t1和t2。

T1類如下所示:

package Test;

public class ThreadOne implements Runnable
{
    @Override
    public void run()
    {
        while (true)
        {
            ThreadUtils.waitForTurn(0);

            //Execute job, code's not here for simplicity
            System.out.println("T1 executed");

            StatusHolder.nextTurn();
        }
    }
}

與T2相同,只是在print語句中將waitForTurn(0)中的0更改為1,並將T1更改為T2。

我的主要內容如下:

package Test;

public class Main
{
    public static void main(String[] args) throws InterruptedException
    {
        Thread t1 = new Thread(new ThreadOne());
        Thread t2 = new Thread(new ThreadTwo());

        t1.start();
        t2.start();

    }
}

所以run方法是這樣的:在循環開始時,線程通過用waitForTurn()調用檢查轉彎值來查看它是否可以起作用:

package Test;

public class ThreadUtils
{
    public static void waitForTurn(int codeNumber)
    { //Wait until turn value is equal to the given number

        synchronized (StatusHolder.getStatusHolder())
        {
            while (StatusHolder.getTurn() != codeNumber)
            {
                try
                {
                    StatusHolder.getStatusHolder().wait();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

如果兩個值相等,則線程執行,否則線程等待nextTurn()調用喚醒StatusHolder對象,因為當轉彎值更改時,所有線程均被喚醒,以便它們可以檢查新的轉彎值是否為他們正在等待的那個,以便他們可以運行。

請注意,nextTurn()在0和1之間循環,這是因為在這種情況下,我只有兩個線程,第一個線程在turn標志為0時執行,第二個線程在turn標志為1時執行,然后再次為0,依此類推。 通過更改此值,我可以輕松更改匝數。

問題:如果我運行它,一切運行正常,並且似乎可以正常工作,但是即使程序根本不會崩潰,輸出控制台也會突然停止運行。 我試圖先放置一個t1.join(),然后再打印一個,但是該打印永遠不會執行,這意味着這些線程永遠不會停止/死掉,而是有時保持鎖定狀態。 如果我放置三個線程,這似乎更加明顯:它比兩個線程更早停止。

我對線程還比較陌生,所以我可能在這里缺少真正愚蠢的東西...

編輯:我不想每次都刪除一個線程並創建一個新線程:每秒創建和刪除數千個obj對於垃圾收集器來說似乎是一個很大的工作量。

我之所以使用線程而不是函數的原因是,在我的實際應用程序中(此代碼只是簡化了)在某個特定的回合中實際上有多個線程必須並行運行,例如:將一個線程轉為1,將一個線程轉為1 2個一線,轉3個30線,重復。 因此,我想為什么不同時為單個功能創建線程並使整個順序考慮。

您可以使用信號量類更簡單

類t1:

public class t1 implements Runnable{
   private Semaphore s2;
     private Semaphore s1;
    public t1(Semaphore s1,Semaphore s2){
    this.s1=s1;
    this.s2=s2;
    }
      public void run()
    {
        while (true)
        {
            try {
                s1.acquire();
            } catch (InterruptedException ex) {
                Logger.getLogger(t1.class.getName()).log(Level.SEVERE, null, ex);
            }

            //Execute job, code's not here for simplicity
            System.out.println("T1 executed");
       s2.release();

        }
    }
}

第2類:

public class t2 implements Runnable{
    private Semaphore s2;
     private Semaphore s1;
    public t2(Semaphore s1,Semaphore s2){
    this.s1=s1;
    this.s2=s2;
    }

      public void run()
    {
        while (true)
        {
            try {
                s2.acquire();
            } catch (InterruptedException ex) {
                Logger.getLogger(t2.class.getName()).log(Level.SEVERE, null, ex);
            }

            //Execute job, code's not here for simplicity
            System.out.println("T2 executed");

            s1.release();
        }
    }
}

類主要:

public class Testing {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
         Semaphore s2=new Semaphore(0);
         Semaphore s1=new Semaphore(1);
       Thread th1 = new Thread(new t1(s1,s2));
        Thread th2 = new Thread(new t2(s1,s2));

        th1.start();
        th2.start();
}}

這是一個不好的方法。 多個線程使您可以同時執行任務。 “一個接一個地執行”動作是單個線程的工作。

只是做這樣的事情:

List<Runnable> tasks = new ArrayList<>();
tasks.add(new ThreadOne()); /* Pick better names for tasks */
tasks.add(new ThreadTwo());
...
ExecutorService worker = Executors.newSingleThreadExecutor();
worker.submit(() -> {
    while (!Thread.interrupted()) 
        tasks.forEach(Runnable::run);
});
worker.shutdown();

當您的應用程序干凈退出時,調用worker.shutdownNow()在這些周期結束時停止這些任務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM