首页 文章

在循环期间线程等待

提问于
浏览
1

我的应用程序有1个全局驱动程序,负责执行低级别的工作 . 然后我有2个线程,这两个线程都使用无限循环来完成一些工作 . 我的问题是如何允许1个线程尽可能多地使用驱动程序,但是有机会让第二个线程在必要时使用它 .

详细说明,我的代码如下:

public class Game {
    private static final Object LOCK = new Object();
    private static final Logger LOGGER = Logger.getLogger(Game.class);

    private WebDriverController controller;

    public Game(WebDriverController controler) {
        this.controller = controller;
    }

    public void startThreadA() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (LOCK) {
                        controller.doSomethingA();
                    }
                }
            }
        }).start();
    }

    public void startThreadB() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    ...
                    ...
                    synchronized (LOCK) {
                        controller.doSomethingB();
                    }
                    ...
                    ...
                }
            }
        }).start();
    }
}

逻辑是允许第一个线程尽可能多地执行 doSomethingA() ,第二个线程只获取锁以完成小任务,然后将锁返回给第一个线程 .

使用此代码,第一个线程将继续使用控制器执行它需要执行的操作,而第二个线程在其同步块中等待等待 . 我目前修复此问题的方法是在第一个线程中添加一个暂停,为第二个线程提供获取锁定的机会,如下所示:

public void startThreadA() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                synchronized (LOCK) {
                    controller.doSomethingA();
                }
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    LOGGER.error(null, e);
                }
            }
        }
    }).start();
}

这确实按预期工作,但似乎并不正确 . 我不满意每次迭代后的手动暂停,特别是如果第二个线程不需要锁定,因为它浪费时间 .

我该如何替换暂停以提高效率?

5 回答

  • -1

    我认为你正在从错误的方向接近这个,因为在你当前的设置中,99.999%的时间线程A要求监视器处理时间被浪费 . 但是,由于我没有足够的有关您实际问题的详细信息,因此这是使用具有公平调度(FIFO)的ReentrantLock的快速解决方案:

    protected final ReentrantLock lock = new ReentrantLock(true); // fair scheduling
    
    public void functionA() {
      lock.lock();
      try {
        controller.functionA();
      } finally {
        lock.unlock();
      }
    }
    
    public void functionB() {
      lock.lock();
      try {
        controller.functionB();
      } finally {
        lock.unlock();
      }
    }
    

    Explanation:

    如果线程A当前持有锁和线程B调用,则B保证在A释放后立即接收监视器,即使A立即(在任何线程切换发生之前)再次调用它 .

  • 0

    为什么在 run() 中使用 synchronized ?在 WebDriverController 中的方法中使用 synchronizedLock .

    public void doSomeThingA(){
       lock.lock();
       try {
          //your stuff
       } finally {
           lock.unlock();
       }
    }
    

    并且在Thread的run方法中调用这些方法 .

  • 1

    这里有一些选择 . 在这个实例中最好的选择可能是消除决定何时从线程执行工作的责任,而是等待来自监视器的事件以释放线程以执行工作 . 然后,您可以按照最适合目的的比例安排工作 .

    或者,从控制器代码中删除缺少线程安全性 .

  • -2

    假设上面的线程组织是你的特定情况的最佳方式,你的问题是第一个线程持有锁太长,从而使第二个线程挨饿 .

    您可以检查doSomethingA函数在执行时是否确实需要锁定驱动程序(在大多数情况下它不会),如果没有将它拆分为多个较小的执行块,其中一些执行锁定而另一些不执行锁定 . 这将为第二个线程创建更多时间,以便在需要时启动 .

    如果无法做到这一点,那么您确实需要重新考虑您的应用,因为您已经创建了资源瓶颈 .

  • -1

    它看起来像 Thread.yield () 正是你要找的 .

相关问题