简体   繁体   English

Java多线程-运行线程仅按顺序运行一次方法

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

In my applications there are an n number of actions that must happen, one after the other in sequence, for the whole life of the program. 在我的应用程序中,整个程序的整个生命周期内必须执行n个动作,一个接一个地执行。 Instead of creating methods which implement those actions and calling them in order in a while(true) loop, I decided to create one thread for each action, and make them execute their run method once, then wait until all the other threads have done the same, wait for its turn, and re-execute again, and so on... 我决定不创建实现这些动作的方法并在while(true)循环中依次调用它们,而是决定为每个动作创建一个线程,并使它们执行一次run方法,然后等待所有其他线程完成操作。同样,等待轮到它,然后重新执行,依此类推...

To implement this mechanism I created a class called StatusHolder, which has a single field called threadTurn (which signifies which thread should execute), a method to read this value, and one for updating it. 为了实现此机制,我创建了一个名为StatusHolder的类,该类具有一个名为threadTurn的字段(表示应执行哪个线程),一种读取该值的方法以及一个用于更新该值的方法。 (Note, this class uses the Singleton design pattern) (请注意,此类使用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;
    }
}

Then I have, let's say, two threads which must be execute in the way explained above, t1 and t2. 然后,我有两个必须以上述方式执行的线程t1和t2。

T1 class looks like this: 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();
        }
    }
}

And T2 its the same, just change 0 to 1 in waitForTurn(0) and T1 to T2 in the print statement. 与T2相同,只是在print语句中将waitForTurn(0)中的0更改为1,并将T1更改为T2。

And my main is the following: 我的主要内容如下:

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

    }
}

So the run method goes like this: At the start of the loop the thread looks if it can act by checking the turn value with the waitForTurn() call: 所以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();
                }
            }
        }
    }
}

If the two values are equal, the thread executes, otherwise it waits on the StatusHolder object to be awaken from the nextTurn() call, because when the turn value changes all the threads are awaken so that they can check if the new turn value is the one they are waiting for so they can run. 如果两个值相等,则线程执行,否则线程等待nextTurn()调用唤醒StatusHolder对象,因为当转弯值更改时,所有线程均被唤醒,以便它们可以检查新的转弯值是否为他们正在等待的那个,以便他们可以运行。

Note thatnextTurn() cycles between 0 and 1: that is because in this scenario I just have two threads, the first executes when the turn flag is 0, and the second when its 1, and then 0 again and so on. 请注意,nextTurn()在0和1之间循环,这是因为在这种情况下,我只有两个线程,第一个线程在turn标志为0时执行,第二个线程在turn标志为1时执行,然后再次为0,依此类推。 I can easily change the number of turns by changing this value. 通过更改此值,我可以轻松更改匝数。

The problem: If I run it, all goes well and seems to work, but suddenly the output console stops flowing, even if the program doesn't crash at all. 问题:如果我运行它,一切运行正常,并且似乎可以正常工作,但是即使程序根本不会崩溃,输出控制台也会突然停止运行。 I tried to put a t1.join() and then a print in the main but that print never executes, this means that the threads never stop/dies, but instead they remain locked sometimes. 我试图先放置一个t1.join(),然后再打印一个,但是该打印永远不会执行,这意味着这些线程永远不会停止/死掉,而是有时保持锁定状态。 This looks to be even more evident if I put three threads: it stops even sooner than with two threads. 如果我放置三个线程,这似乎更加明显:它比两个线程更早停止。

I'm relatively new to threads, so I might be missing something really stupid here... 我对线程还比较陌生,所以我可能在这里缺少真正愚蠢的东西...

EDIT: I'd prefer not to delete a thread and create a new one every time: creating and deleting thousands of objs every second seems a big work load for the garbage collector. 编辑:我不想每次都删除一个线程并创建一个新线程:每秒创建和删除数千个obj对于垃圾收集器来说似乎是一个很大的工作量。

The reason why I'm using threads and not functions is because in my real application (this code is just simplified) at a certain turn there actually are multiple threads that must run (in parallel), for example: turn 1 one thread, turn 2 one thread, turn 3 30 threads, repeat. 我之所以使用线程而不是函数的原因是,在我的实际应用程序中(此代码只是简化了)在某个特定的回合中实际上有多个线程必须并行运行,例如:将一个线程转为1,将一个线程转为1 2个一线,转3个30线,重复。 So I thought why not creating threads also for the single functions and make the whole think sequential. 因此,我想为什么不同时为单个功能创建线程并使整个顺序考虑。

you can use Semaphore class it's more simple 您可以使用信号量类更简单

class t1 : 类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();

        }
    }
}

class t2: 第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();
        }
    }
}

class main: 类主要:

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

This is a bad approach. 这是一个不好的方法。 Multiple threads allow you to execute tasks concurrently. 多个线程使您可以同时执行任务。 Executing actions "one after the other in sequence" is a job for a single thread. “一个接一个地执行”动作是单个线程的工作。

Just do something like this: 只是做这样的事情:

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

Call worker.shutdownNow() when your application is cleanly exiting to stop these tasks at the end of their cycle. 当您的应用程序干净退出时,调用worker.shutdownNow()在这些周期结束时停止这些任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM