Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用“暂停-然后恢复”或其他选项在线程之间同步共享数据_Java_Multithreading_Resume_Suspend - Fatal编程技术网

Java 如何使用“暂停-然后恢复”或其他选项在线程之间同步共享数据

Java 如何使用“暂停-然后恢复”或其他选项在线程之间同步共享数据,java,multithreading,resume,suspend,Java,Multithreading,Resume,Suspend,我正在写一个游戏,其中一个线程-游戏线程-永远循环,更新我所有的精灵,渲染它们,然后在再次执行之前睡眠一段时间。我还有一个定制的事件处理程序,用于处理按键等 在大多数情况下,这一切都很好。但是,如果在GameThread渲染时引发事件,我会遇到一个问题。在极少数情况下,处理事件的处理程序可能会同时更改需要渲染的内容,从而影响GameThread渲染的结果 为了避免这种情况,我希望事件处理程序立即暂停游戏线程,处理事件,然后恢复游戏线程 suspend()/resume()方法适合我的需要,但它们

我正在写一个游戏,其中一个线程-游戏线程-永远循环,更新我所有的精灵,渲染它们,然后在再次执行之前睡眠一段时间。我还有一个定制的事件处理程序,用于处理按键等

在大多数情况下,这一切都很好。但是,如果在GameThread渲染时引发事件,我会遇到一个问题。在极少数情况下,处理事件的处理程序可能会同时更改需要渲染的内容,从而影响GameThread渲染的结果

为了避免这种情况,我希望事件处理程序立即暂停游戏线程,处理事件,然后恢复游戏线程

  • suspend()
    /
    resume()
    方法适合我的需要,但它们已被弃用。然而,在我的例子中,由于死锁的可能性很小,不管怎样使用它们是否安全

  • 如果没有,我还有哪些不需要大量开销的替代方案

  • 我看到一个建议,通过在要暂停的线程中设置一个标志来请求暂停线程。然而,在我的例子中,我不认为这是一个可行的选择,因为GameThread循环在循环的迭代过程中可能需要一段时间。我将无法检查标志,直到我完成了循环,到那时已经太晚了


    我需要立即暂停,否则用户将注意到事件处理延迟

    如果要同步对资源的访问,请使用ReentrantLock:

    ReentrantLock sync=新的ReentrantLock()

    您必须将该锁传递给要访问共享数据的每个runnable

    然后,在您访问相关资源的每个地方,您将使用该共享锁对象,并获取并释放锁(即,您的关键部分):

    这是java中相当标准的并发编程。请记住,“lock”是一种阻塞方法,因此您可能希望改用“tryLock”,它允许您尝试获取锁,但会返回一个布尔值,说明您是否实际获得了锁:

     if (sync.tryLock()) {
       try {
         //critical section
       }
       finally {
         sync.unlock();
       }
     }
    

    有一个版本的“tryLock”会等待给定的时间,然后放弃获取锁并返回假值。

    通常,您会执行一些线程同步:

    这将允许您执行正在执行的两件事情之一:要么在游戏渲染线程中渲染,要么根据事件进行更改

    您所面临的问题似乎是渲染代码花费的时间太长,无法真正获得平滑的体验(即,在渲染某些内容时,许多事件可能会堆积起来进行处理)。在这种情况下,应该使用能够快速完成并在其上同步的独立片段进行渲染

    如果没有任何代码,我无法给您提供具体的建议,但通常情况下会是这样的:

    List<Shape> shapesToRender;
    Object lockObject = new Object(); // Note this must be somehow shared between two threads
    
    // Your rendering thread method
    public void renderForever() {
      while(true) {
        for(Shape shape: shapesToRender) {
          synchronized(lockObject) {
            render(shape);
          }
        }
      }
    }
    
    // One of your event handlers
    public void handleEvent(Event event) {
      synchronized(lockObject) {
        // Process event somehow, e.g. change the color of some of the shapes
        event.getShape().setColor(Color.RED);
      }
    }
    
    列表shapesToRender;
    对象锁定对象=新对象();//注意,这必须以某种方式在两个线程之间共享
    //渲染线程方法
    public void renderForever(){
    while(true){
    用于(形状:shapesToRender){
    已同步(锁定对象){
    渲染(形状);
    }
    }
    }
    }
    //您的事件处理程序之一
    公共无效handleEvent(事件){
    已同步(锁定对象){
    //以某种方式处理事件,例如更改某些形状的颜色
    event.getShape().setColor(Color.RED);
    }
    }
    
    在上述情况下:

    • 您将渲染一个形状(所有事件处理程序都将等待该形状完成),或者
    • 一些事件处理程序将执行某些操作(渲染线程将等待该操作完成)
    您应该更深入地了解这个Java线索:

    由于还有其他解决方案,例如使用锁定对象:

    或同时收集:

    这取决于您的问题,可能更容易,而且最重要的是,这是一个经过良好测试的解决方案,它允许您以标准方式执行某些操作,从而避免了在推出自定义线程代码时可能遇到的所有陷阱

    希望这有帮助

    suspend()/resume()方法适合我的需要,但它们已被弃用。然而,在我的例子中,由于死锁的可能性很小,不管怎样使用它们是否安全

    显然,如果死锁的可能性为零,那么它是安全的。但是有各种各样意想不到的方法会导致僵局。例如,您可能会在线程初始化类时暂停线程。。。这将使试图引用该类的静态字段的任何其他线程死锁。(这是JVM指定行为的结果。在其他地方,未指定在引擎盖下进行的锁定/同步。这很公平。不需要这样做……除非您考虑使用这些不推荐的方法。)

    因此,现实是很难确定(证明)它是否真的安全。如果你不能确定这一点,那么这是一件有潜在风险的事情。这就是这些方法被弃用的原因


    (严格地说,这不是死锁。死锁是指线程永远无法继续。在这种情况下,如果可以恢复暂停的线程,其他线程也可以继续。)

    暂停/恢复被弃用的原因是,很难正确暂停/恢复线程,这要由应用程序开发人员来处理。具有共享标志的解决方案是最常用的。你能发布一些示例代码吗?我认为使用flag并仍然有响应应用程序是可能的。我会避免“synchronized”块,尽管这种方法是有效的(请参阅我发布的答案)。原因是“synchronized”块无法控制阻塞。使用ReentrantLock可以完成一些事情
    List<Shape> shapesToRender;
    Object lockObject = new Object(); // Note this must be somehow shared between two threads
    
    // Your rendering thread method
    public void renderForever() {
      while(true) {
        for(Shape shape: shapesToRender) {
          synchronized(lockObject) {
            render(shape);
          }
        }
      }
    }
    
    // One of your event handlers
    public void handleEvent(Event event) {
      synchronized(lockObject) {
        // Process event somehow, e.g. change the color of some of the shapes
        event.getShape().setColor(Color.RED);
      }
    }