Java Gameboy仿真-SwingWorker卡在Unsafe.park

Java Gameboy仿真-SwingWorker卡在Unsafe.park,java,swing,swingworker,emulation,gameboy,Java,Swing,Swingworker,Emulation,Gameboy,我正在为Gameboy系统制作一个模拟器,并使用Swing作为我的GUI。我的实现使用SwingWorker在后台线程中运行CPU仿真。通过SwingWorker.doInBackground方法,我发布了一个包含帧缓冲区(图像数据)的数组,每隔一定的时间(每当Gameboy模拟VBlank屏幕刷新时)发布一次,预计每秒刷新60次。我在这个后台线程中调用Thread.sleep(…),使Gameboys时间与系统时间同步。在process方法中,我将此数据传递到JPanel并调用其repaint

我正在为Gameboy系统制作一个模拟器,并使用Swing作为我的GUI。我的实现使用
SwingWorker
在后台线程中运行CPU仿真。通过
SwingWorker.doInBackground
方法,我发布了一个包含帧缓冲区(图像数据)的数组,每隔一定的时间(每当Gameboy模拟VBlank屏幕刷新时)发布一次,预计每秒刷新60次。我在这个后台线程中调用
Thread.sleep(…)
,使Gameboys时间与系统时间同步。在
process
方法中,我将此数据传递到
JPanel
并调用其
repaint
方法。我的
doInBackground
方法基本上是一个无限循环,模拟的Gameboy CPU在后台不断执行指令

我面临的问题是,在某些ROM上,我的应用程序只是冻结,而我的
JPanel
组件没有显示屏幕更新。我尝试在后台运行线程上使用
println
,输出被模拟CPU执行的指令,但这也被卡住了,一段时间后没有生成任何输出

对于一些ROM,我根本看不到这个问题发生

以下是我的SwingWorker代码示例:

package com.sankar.gbemu.swing;

import com.sankar.gbemu.cpu.CPU;
import com.sankar.gbemu.gpu.LCDController;
import com.sankar.gbemu.gpu.VBlankListener;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class EmulationWorker extends SwingWorker<Void,int[][]> {


private CPU cpu;
private LCDController lcd;
private GBPanel panel;
private GBRenderer renderer;

public EmulationWorker(CPU cpu, LCDController lcd, GBPanel panel, GBRenderer renderer) {
    this.cpu = cpu;
    this.lcd = lcd;
    this.panel = panel;
    this.renderer = renderer;
    init();
}

private void init() {
    lcd.registerVBlankListener(new VBlankListener() {

        private long lastRefresh = System.nanoTime();

        private static final long REFRESH_INTERVAL = (long)1e9/60;

        @Override
        public void vBlankOccured(int[][] screenData) {
            publish(screenData);

            long currentTime = System.nanoTime();
            long delta = currentTime - lastRefresh;

            lastRefresh = currentTime;

            if (delta < REFRESH_INTERVAL) {
                try {
                    long sleepInterval = (long)((REFRESH_INTERVAL - delta)/1e6);
                    Thread.sleep(sleepInterval);
                } catch(InterruptedException e) {
                    // Ignore
                }
            }
        }
    });
}

@Override
protected Void doInBackground() throws Exception {
    while(true) cpu.step();
}

@Override
protected void process(List<int[][]> updates) {
    if (!SwingUtilities.isEventDispatchThread()) throw new RuntimeException("Not in event dispatch thread");
    renderer.updateScreenData(updates.get(updates.size() - 1));
    panel.repaint();
}

}
package com.sankar.gbemu.swing;
导入com.sankar.gbemu.cpu.cpu;
导入com.sankar.gbemu.gpu.lcd控制器;
导入com.sankar.gbemu.gpu.vb;
导入java.util.List;
导入javax.swing.SwingUtilities;
导入javax.swing.SwingWorker;
公共类EmulationWorker扩展SwingWorker{
专用CPU;
专用液晶控制器;
私人GBPanel小组;
私人GBP;
公共仿真工作者(CPU、lcd控制器lcd、GBPanel面板、GBRenderer渲染器){
this.cpu=cpu;
this.lcd=lcd;
this.panel=面板;
this.renderer=渲染器;
init();
}
私有void init(){
lcd.registerBlankListener(新的VBlankListener(){
private long lastresh=System.nanoTime();
专用静态最终长刷新间隔=(长)1e9/60;
@凌驾
出现公共无效数据(int[][]屏幕数据){
发布(屏幕数据);
长currentTime=System.nanoTime();
长增量=当前时间-上次刷新;
lastRefresh=当前时间;
if(增量<刷新间隔){
试一试{
长睡眠间隔=(长)((刷新间隔-增量)/1e6);
睡眠(睡眠间隔);
}捕捉(中断异常e){
//忽略
}
}
}
});
}
@凌驾
受保护的Void doInBackground()引发异常{
while(true)cpu.step();
}
@凌驾
受保护的无效进程(列表更新){
如果(!SwingUtilities.isEventDispatchThread())抛出新的RuntimeException(“非事件调度线程”);
renderer.updateScreenData(updates.get(updates.size()-1));
panel.repaint();
}
}
我进行了jstack跟踪,发现我的swing worker线程卡在了Unsafe.park上:

2013-10-10 22:17:18
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.0-b56 mixed mode):

"Attach Listener" daemon prio=5 tid=0x00007fae12049000 nid=0xc20f waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"TimerQueue" daemon prio=5 tid=0x00007fae1240b800 nid=0xbf03 waiting on condition [0x000000015a085000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x000000013ac88b60> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
    at java.util.concurrent.DelayQueue.take(DelayQueue.java:209)
    at javax.swing.TimerQueue.run(TimerQueue.java:171)
    at java.lang.Thread.run(Thread.java:724)

"SwingWorker-pool-1-thread-1" daemon prio=5 tid=0x00007fae11194800 nid=0xb92f waiting on condition [0x0000000159f82000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x000000013ac2c340> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
    at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)

"Java2D Disposer" daemon prio=5 tid=0x00007fae11183000 nid=0xac03 in Object.wait() [0x0000000157915000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000013ad250c0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
    - locked <0x000000013ad250c0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
    at sun.java2d.Disposer.run(Disposer.java:145)
    at java.lang.Thread.run(Thread.java:724)

"Java2D Queue Flusher" daemon prio=5 tid=0x00007fae11106800 nid=0x9f0b in Object.wait() [0x0000000156eb0000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000013ac57f18> (a sun.java2d.opengl.OGLRenderQueue$QueueFlusher)
    at sun.java2d.opengl.OGLRenderQueue$QueueFlusher.run(OGLRenderQueue.java:208)
    - locked <0x000000013ac57f18> (a sun.java2d.opengl.OGLRenderQueue$QueueFlusher)

"DestroyJavaVM" prio=5 tid=0x00007fae12003000 nid=0x1007 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"AWT-EventQueue-0" prio=5 tid=0x00007fae110ec800 nid=0x9d03 waiting on condition [0x0000000156dad000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x000000013ac8b3f0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
    at java.awt.EventQueue.getNextEvent(EventQueue.java:543)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

"AWT-Shutdown" prio=5 tid=0x00007fae110d5800 nid=0x6e03 in Object.wait() [0x0000000154562000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000013ad26900> (a java.lang.Object)
    at java.lang.Object.wait(Object.java:503)
    at sun.awt.AWTAutoShutdown.run(AWTAutoShutdown.java:287)
    - locked <0x000000013ad26900> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:724)

"AppKit Thread" daemon prio=5 tid=0x00007fae12120000 nid=0x2617 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Service Thread" daemon prio=5 tid=0x00007fae12081000 nid=0x5703 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=5 tid=0x00007fae12078800 nid=0x5503 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=5 tid=0x00007fae1207f000 nid=0x5303 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=5 tid=0x00007fae12077800 nid=0x5103 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=5 tid=0x00007fae12043000 nid=0x3e03 in Object.wait() [0x000000015283c000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000013ac08d80> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
    - locked <0x000000013ac08d80> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:189)

"Reference Handler" daemon prio=5 tid=0x00007fae12040800 nid=0x3c03 in Object.wait() [0x0000000152739000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000013ac08ad0> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:503)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
    - locked <0x000000013ac08ad0> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=5 tid=0x00007fae12040000 nid=0x3a03 runnable 

"GC task thread#0 (ParallelGC)" prio=5 tid=0x00007fae1200f800 nid=0x3603 runnable 

"GC task thread#1 (ParallelGC)" prio=5 tid=0x00007fae12010000 nid=0x3803 runnable 

"VM Periodic Task Thread" prio=5 tid=0x00007fae12089800 nid=0x5903 waiting on condition 

JNI global references: 344
2013-10-1022:17:18
全线程转储Java热点(TM)64位服务器VM(24.0-b56混合模式):
“附加侦听器”守护程序prio=5 tid=0x00007fae12049000 nid=0xc20f等待条件[0x0000000000000000]
java.lang.Thread.State:可运行
“TimerQueue”守护进程prio=5 tid=0x00007fae1240b800 nid=0xbf03等待条件[0x000000015a085000]
java.lang.Thread.State:等待(停车)
在sun.misc.Unsafe.park(本机方法)
-停车等待(java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
位于java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
位于java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
位于java.util.concurrent.DelayQueue.take(DelayQueue.java:209)
在javax.swing.TimerQueue.run(TimerQueue.java:171)
运行(Thread.java:724)
“SwingWorker-pool-1-thread-1”守护进程prio=5 tid=0x00007fae11194800 nid=0xb92f等待条件[0x0000000159f82000]
java.lang.Thread.State:等待(停车)
在sun.misc.Unsafe.park(本机方法)
-停车等待(java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
位于java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
位于java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
位于java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
位于java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
位于java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
位于java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
运行(Thread.java:724)
Object.wait()中的“Java2D Disposer”守护进程prio=5 tid=0x00007fae11183000 nid=0xac03[0x0000000157915000]
java.lang.Thread.State:正在等待(在对象监视器上)
在java.lang.Object.wait(本机方法)
-等待(java.lang.ref.ReferenceQueue$Lock)
位于java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
-锁定(java.lang.ref.ReferenceQueue$Lock)
位于java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
运行(Disposer.java:145)
运行(Thread.java:724)
对象中的“Java2D队列刷新器”守护程序prio=5 tid=0x00007fae11106800 nid=0x9f0b.wait()[0x0000000156eb0000]
java.lang.Thread.State:定时等待(在对象监视器上)
在java.lang.Object.wait(本机方法)
-等待(sun.java2d.opengl.OGLRenderQueue$QueueFlusher)
位于sun.java2d.opengl.OGLRenderQueue$QueueFlusher.run(OGLRenderQueue.java:208)
-锁定(sun.java2d.opengl.OGLRenderQueue$QueueFlusher)
“DestroyJavaVM”优先级=5 tid=0x00007fae12003000 nid=0x1007等待条件[0x0000000000000000]