【问题标题】:Making sure two threads one after another in a cycle - Android确保两个线程在一个循环中一个接一个 - Android
【发布时间】:2019-11-24 02:54:06
【问题描述】:

我有两个这样开始的线程

    Thread player1Thread = new Thread(new Player1RunnableManual());
    player1Thread.start();
    Thread player2Thread = new Thread(new Player2RunnableManual());
    player2Thread.start();

两名玩家,玩家 1 和玩家 2 以不同的方式猜测 100 个数字,一次一个。我们可以忽略他们用来猜测数字的启发式方法。 我需要确保 player1 先运行,然后 player2 运行,然后 player1 运行,然后 player2 再次运行,直到其中一个猜到特定数字(硬编码)。

我尝试使用可重入锁,但无法使其工作。 player1 和 player2 的可运行文件如下。

我如何编写一个锁实现来使其工作?

class Player1RunnableManual implements Runnable {
    @Override
    public void run() {
        while (!gopherFound) {
            r = new Random();
            final int player1Position = r.nextInt(high - low) + low;
            final int outcome = calculateProximity(player1, player1Position);
            if (outcome != DISASTER) {
                runnableHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (holes[player1Position] == 0) {
                            setPosition(player1, player1Position);
                            player1Status.setText(outcomesList[outcome]);
                        }
                    }
                });
                if (outcome == SUCCESS) {
                    gopherFound = true;
                    winner = "Player 1";
                    result.setText("Player 1 wins");
                    break;
                }
            }
            try {
                int sleep = r.nextInt(threadHigh - threadLow) + threadLow;
                Thread.sleep(sleep);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }
    }
}


class Player2RunnableManual implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 100 && !gopherFound; i++) {
            final int player2Position = i;
            final int outcome = calculateProximity(player2, player2Position);
            if (outcome != DISASTER) {
                Message msg = messageHandler.obtainMessage(player2);
                msg.arg1 = player2Position;
                msg.arg2 = outcome;
                messageHandler.sendMessage(msg);
                if (outcome == SUCCESS) {
                    gopherFound = true;
                    winner = "Player 2";
                    result.setText("Player 2 wins");
                    break;
                }
            }
            try {
                int sleep = r.nextInt(threadHigh - threadLow) + threadLow;
                Thread.sleep(sleep);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }
    }
}

【问题讨论】:

    标签: java android multithreading


    【解决方案1】:

    为什么不使用单线程执行器?可运行对象将被加入队列。

    Executor executor = Executors.newSingleThreadExecutor();
    while(!gopherFound){
        executor.execute(new Player1RunnableManual());
        executor.execute(new Player2RunnableManual());
        // wait here for the end of the 2 runnables, maybe using Future tasks instead of runnables
    }
    

    你可以清理代码,runnables不能再有一个“while(!gopherFound)”,但是这样,你可以确定runnables一个接一个地执行

    另一种方法是使用“Semaphore(1)”,也可以使用“acquire()”和“release()”方法来完成这项工作,但它不能保证首先执行哪个线程。

    【讨论】:

      【解决方案2】:

      为了确保一个动作会一个接一个地触发。您可以简单地使用ThreadPoolExecutor。像下一个。

      final ThreadPoolExecutor executor = 
        (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
      
      executor.submit(new Runnable() {
           @Override 
           public void run() { 
                 // Your action 1
           }
      });
      
      executor.submit(new Runnable() {
           @Override 
           public void run() { 
                 // Your action 2
           }
      })
      

      【讨论】:

        【解决方案3】:

        要让您的player1Threadplayer2Thread 之前开始执行,您需要在开始player2Thread 之前在player1Thread 上调用join。但这意味着player2Thread 不会启动,除非player2Thread 死亡。
        解决此问题的方法是,如果您知道player1Thread 启动后多长时间,应该player2Thread 启动然后将该持续时间(转换为毫秒)作为参数传递给player1Thread 上的join

        使用单线程Executor,依次提交Player1RunnableManualPlayer2RunnableManual。另外,别忘了关闭Executor

        关于您使用Reentrant Lock 的方法。 Reentrent Lock 是使用 synchronized 块的面向对象等效项。您可以通过将一种转换为另一种来进行一些练习。它只执行同步,不保证线程执行顺序。对共享对象的访问将由线程调度程序决定,这有点随机。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-28
          • 2022-07-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-17
          相关资源
          最近更新 更多