Java多线程声音崩溃

Posted

技术标签:

【中文标题】Java多线程声音崩溃【英文标题】:Java Multi-threaded sound crash 【发布时间】:2012-02-26 21:59:00 【问题描述】:

我正在开发一个 Java 游戏项目,我需要能够同时实时播放多个声音。我已经实现了一个声音系统,可以生成新线程来播放 SourceDataLine 声音。

游戏在我的电脑上运行良好,但对于我的一位测试人员来说,音响系统会不时出现在他身上的崩溃。我们都在 Windows 7 上运行相同版本的 java (jre 1.6.0_29),经过几轮测试和谷歌搜索,我无法弄清楚为什么它总是对我很好,但崩溃了在他身上。

这是一个 SSCCE,演示了我的代码中出现问题的部分。重要的部分是 SoundPlayer、Sound 和 SoundThread 类。您需要在保存 SSCCE 的同一目录中包含两个名为 shortSound.wav 和 longSound.wav 的声音文件。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.sound.sampled.*;
import java.util.HashMap;
import java.util.Collection;
import java.io.*;
import java.net.URL;
import java.util.LinkedList;

public class SoundSSCCE extends JFrame


    private JPanel screenP;
    private JPanel bgFraming;

    /**
    *   Constructor
    *   Preconditions: None.
    *   Postconditions: The window for the SSCCE is created.
    **/

    public SoundSSCCE()
    
        super("Sound problem SSCCE");
        this.setSize(200,100);

        // instantiate main window panel

        screenP = new SSCCEPanel(this);
        this.add(screenP);

        // finishing touches on Game window

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        System.out.println("Game Window successfully created!!!");
    


    public static void main(String[] args)
    
        SoundSSCCE gui = new SoundSSCCE();      
    





/**
*   SSCCEPanel is the JPanel that manages the example's timer, painting, and logic. 
**/

class SSCCEPanel extends JPanel

    public Frame parentFrame;
    private Timer timer;
    public int logicLoops;
    public double prevFPS;
    boolean timerReady;

    // The SoundPlayer object is used by the example to play the sounds.

    public SoundPlayer soundPlayer;

    public SSCCEPanel(Frame parent)
    
        super(true);
        parentFrame = parent;
        this.setFocusable(true);

        Toolkit.getDefaultToolkit().sync();
        logicLoops = 0;

        soundPlayer = new SoundPlayer();

        TimerListener timerListener = new TimerListener();
        prevFPS = 0;
        timerReady = true;
        timer = new Timer(0,timerListener);
        this.setFPS(60);
        timer.start();
    

    /** 
    *   setFPS()
    *   Preconditions: fps is a quantity of frames per second
    *   Postconditions: Sets the timer's refresh rate so that it 
    *       fires fps times per second.
    **/

    public void setFPS(int fps)
    
        int mspf = (int) (1000.0 /fps + 0.5);
        timer.setDelay(mspf);
    


    /**
    *   This is the JPanel's timer listener. It runs the example's logic and repaint
    *   methods each time it gets a timer signal.
    **/

    private class TimerListener implements ActionListener
    
        long startTime = System.currentTimeMillis();
        long lastTime = this.startTime;
        int ticks = 0;

        public void actionPerformed(ActionEvent e)
        
            Object source = e.getSource();
            if(source == timer)
            
                // perform a loop through the game's logic and repaint.

                synchronized(this)
                
                    if(timerReady)
                    
                        timerReady = false;
                        runSSCCELogic();
                        repaint();
                        timerReady = true;
                    
                

                // Logic for Frames per Second counter

                this.ticks++;

                long currentTime = System.currentTimeMillis();

                if(currentTime - startTime >= 500) 
                
                    prevFPS =  1000.0 * ticks/(1.0*currentTime - startTime);
                    System.out.println(prevFPS);
                    startTime = currentTime;
                    ticks = 0;
                

                lastTime = currentTime;
            
        
    


    /**
    *   repaints the SSCCE.
    *   This just shows the current FPS and the number of sounds currently playing.
    **/

    public void paintComponent(Graphics g)
    
            super.paintComponent(g);

            Graphics2D g2D = (Graphics2D) g;
            double roundedFPS = Math.round(prevFPS*10)/10.0;

            g2D.setColor(new Color(0x000000));
            g2D.drawString("FPS: " + roundedFPS, 20,20);
            g2D.drawString("Sounds playing: " + soundPlayer.soundsPlaying(), 20,50);
            g.dispose();
    

    /**
    *   runSSCCEELogic()
    *   This is where the run-time logic for the SSCCE example is. 
    *   All it will do is play sounds at regular narrowly-spaced intervals.
    *   The sounds are stored in the same directory as the SSCCE. Substitute any .wav
    *   file here in place of shortSound.wav and longerSound.wav.
    **/

    public void runSSCCELogic()
    
        if(logicLoops % 4 == 0)
        
            soundPlayer.play("shortSound.wav");
        
        if(logicLoops% 40 == 0)
        
            soundPlayer.play("longerSound.wav");
        
        logicLoops++;
    






/**
*   My game uses makes method calls to the SoundPlayer object whenever it
*   needs to play any sounds. This separates the main game code from the lower-level 
*   mucking-about with Sound object code. It also makes it easier for me to make changes to 
*   my Sound class without having to make changes any lines in my game where I play sounds.
**/


class SoundPlayer

    private HashMap<String,Sound> sounds;
    private double volume;
    private int soundsPlaying;

    public SoundPlayer()
    
        sounds = new HashMap<String,Sound>();
        volume = 1.0;
        soundsPlaying = 0;
    


    /**
    *   playSound(String path)
    *   creates and plays a Sound specified by path.
    *   Preconditions: path is the file path for the sound.
    *   Postconditions: The sound is loaded and begins playing. 
    *       This method returns a reference to that sound.
    **/

    public Sound play(String path)
           
        Sound newSound;

        if(volume == 0)
            return null;

        if(sounds.containsKey(path))
        
            newSound = sounds.get(path);
        
        else
        
            newSound = new Sound(path);
            sounds.put(path,newSound);
        

        newSound.play(volume);

        return newSound;
    

    /**
    *   load(String path)
    *   preloads a sound to be play instances of at a later time
    *   Preconditions: path is the file path for the sound.
    *   Postconditions: The sound is loaded. This method returns 
    *       a reference to that sound.
    **/

    public Sound load(String path)
    
        Sound newSound;

        if(sounds.containsKey(path))
        
            newSound = sounds.get(path);
        
        else
        
            newSound = new Sound(path);
            sounds.put(path,newSound);
        
        return newSound;
    

    public int soundsPlaying()
    
        int count = 0;

        Collection<Sound> soundsIterable = sounds.values();
        for(Sound sound : soundsIterable)
        
            count += sound.instances;
        
        return count;
    

    public int soundsLoaded()
    
        return sounds.size();
    


    public void setVolume(double vol)
    
        this.volume = vol;
    




/**
*   Sound objects store the path to a given sound file and spawn new threads
*   to play instances of their sound when the SoundPlayer tells them to play.
**/

class Sound

    public String path;
    protected int instances;
    protected URL soundURL;

    public Sound(String name)
    
        try
        
            soundURL =  getClass().getClassLoader().getResource(name);
            instances = 0;
            path = name;
        
        catch(Exception ex)
        
            System.out.println("An error occured while loading the sound file: " + name);
            System.out.println(ex.getMessage());
            ex.printStackTrace();
        
    

    /**
    *   play(double volume)
    *   Preconditions: volume is between 0.0 and 1.0 inclusive, where 1.0 is 
    *       at full volume and 0.0 is silent.
    *   Postconditions: The Sound spawns a new thread to play an instance
    *       of itself.
    **/

    public void play(double volume)
    
        try
        
            SoundThread clip = new SoundThread(this);
            synchronized(this)
            
                // increment the count of its instances. The SoundThread
                //  will automatically decrement the sound instance when it finishes. 

                instances++;
            
            clip.setVolume(volume);
            clip.start();

        
        catch(Exception e)
        
            System.out.println("Sound error: Error playing sound");
            System.out.println(e.getMessage());
            e.printStackTrace();
        
    



/**
*   SoundThread is a thread that Sound objects spawn to play instances 
*   of their sounds. This supports multiple sounds being played simultaneously. 
**/

class SoundThread extends Thread

    public SourceDataLine clip;
    public AudioInputStream stream;
    private int bufferSize = 50;
    private Sound parent;

    public SoundThread(Sound parentSound)
    
        try
        
            parent = parentSound;

            // obtains input stream from Audiosystem to read from the file.

            stream = AudioSystem.getAudioInputStream(parentSound.soundURL); 
            AudioFormat format = stream.getFormat();

            // obtains the sound file's line

            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 

            // loads the line into the clip

            clip = (SourceDataLine) AudioSystem.getLine(info); 

            // opens the clip onto the stream

            clip.open(format); 
            System.out.println("Sound buffer size: " + clip.getBufferSize());
        
        catch(Exception e)
        
            System.out.println("error playing sound");
            System.out.println(e.getMessage());
            e.printStackTrace();
        
    


    public void run()
    
        try
        
            // I start my sourceDataLine and begin reading data 
            // from the stream into its buffer.

            clip.start();
            int bytesRead = 0;
            byte[] soundData = new byte[bufferSize];

            // read data from the stream into the sourceDataLine until there
            // is no more data to read

            while(bytesRead != -1)
            
                bytesRead = stream.read(soundData,0,bufferSize);
                if(bytesRead >= 0)
                
                    clip.write(soundData, 0, bytesRead);
                
                else
                
                    // Here I drain and close the line and its stream when
                    //  the sound is finished playing (it has read all the bytes from its stream).
                    // My tester's log suggests that SourceDataLine.drain() is where it
                    // is crashing.

                    clip.drain();
                    clip.close();
                    stream.close();
                
            

            // decrement the count of the Sound's instances.

            synchronized(parent)
            
                parent.instances--;
            
        
        catch(Exception e)
        
            System.out.println(e.getMessage());
            e.printStackTrace();
        
    



    public void setVolume(double vol)
    
        try
        
            FloatControl volCtrl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
            if(vol > 1.0)
                vol = 1.0;
            if(vol < 0.0)
                vol = 0.0;

            // tricky, confusing sound math stuff.

            float dB = (float) (Math.log(vol) / Math.log(10.0) * 20.0);
            if(dB > volCtrl.getMaximum())
                dB = volCtrl.getMaximum();
            if(dB < volCtrl.getMinimum())
                dB = volCtrl.getMinimum();
            volCtrl.setValue(dB);
        
        catch(Exception e)
        
            System.out.println("set volume failed");
            System.out.println(e.getMessage());
            e.printStackTrace();
        
    

这是我的测试人员的 jre 在游戏崩溃时生成的日志文件。

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000000000000, pid=5212, tid=5524
#
# JRE version: 6.0_29-b11
# Java VM: Java HotSpot(TM) 64-Bit Server VM (20.4-b02 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  0x0000000000000000
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

---------------  T H R E A D  ---------------

Current thread (0x00000000097c4000):  JavaThread "Thread-651" [_thread_in_native, id=5524, stack(0x000000000ecf0000,0x000000000edf0000)]

siginfo: ExceptionCode=0xc0000005, ExceptionInformation=0x0000000000000008 0x0000000000000000

Registers:
RAX=0x0000000000000000, RBX=0x00000000148ef5b0, RCX=0x00000000097c41d0, RDX=0x0000000000000002
RSP=0x000000000edef4f8, RBP=0x000000000edef6e0, RSI=0x00000000097c41d0, RDI=0x00000000097c41d0
R8 =0x000000000edef520, R9 =0x0000000000000000, R10=0x2b11000000000000, R11=0x0000000006146b00
R12=0x00000000148a1f00, R13=0x0000000000000000, R14=0x000000000edef710, R15=0x00000000097c4000
RIP=0x0000000000000000, EFLAGS=0x0000000000010246

Top of Stack: (sp=0x000000000edef4f8)
0x000000000edef4f8:   000000006d515842 000000000edef5a0
0x000000000edef508:   0000000000000000 000000000bfbbd18
0x000000000edef518:   000000006d525264 00000000148ef5b0
0x000000000edef528:   0000000006146b00 000000001491ddb0
0x000000000edef538:   2b11000000001f44 00000000096b0108
0x000000000edef548:   0000000000000000 000000006d90a5cb
0x000000000edef558:   000000006d511ed4 00000000097c41d0
0x000000000edef568:   000000006d511ed4 00000000148ef5b0
0x000000000edef578:   000000006d516055 0000000000000000
0x000000000edef588:   0000000000000000 0000000000000000
0x000000000edef598:   0000000000000000 00000000148ef5b0
0x000000000edef5a8:   0000000006146b00 000000001491ed56
0x000000000edef5b8:   2b11000000000000 00000000096b0108
0x000000000edef5c8:   0000000000000000 000000006d90a5cb
0x000000000edef5d8:   000000006d52b54b 00000000000005c8
0x000000000edef5e8:   00000000bc162e50 0000000000000000 

Instructions: (pc=0x0000000000000000)
0xffffffffffffffe0:   


Register to memory mapping:

RAX=0x0000000000000000 is an unknown value
RBX=0x00000000148ef5b0 is an unknown value
RCX=0x00000000097c41d0 is an unknown value
RDX=0x0000000000000002 is an unknown value
RSP=0x000000000edef4f8 is pointing into the stack for thread: 0x00000000097c4000
RBP=0x000000000edef6e0 is pointing into the stack for thread: 0x00000000097c4000
RSI=0x00000000097c41d0 is an unknown value
RDI=0x00000000097c41d0 is an unknown value
R8 =0x000000000edef520 is pointing into the stack for thread: 0x00000000097c4000
R9 =0x0000000000000000 is an unknown value
R10=0x2b11000000000000 is an unknown value
R11=0x0000000006146b00 is a global jni handle
R12=0x00000000148a1f00 is an unknown value
R13=0x0000000000000000 is an unknown value
R14=0x000000000edef710 is pointing into the stack for thread: 0x00000000097c4000
R15=0x00000000097c4000 is a thread


Stack: [0x000000000ecf0000,0x000000000edf0000],  sp=0x000000000edef4f8,  free space=1021k
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  com.sun.media.sound.MixerSourceLine.nDrain(J)V+0
j  com.sun.media.sound.MixerSourceLine.drain()V+26
J  gameEngine.SoundThread.run()V
v  ~StubRoutines::call_stub

---------------  P R O C E S S  ---------------

Java Threads: ( => current thread )
  0x0000000009959000 JavaThread "Thread-1843" [_thread_in_native, id=4748, stack(0x0000000015780000,0x0000000015880000)]
  0x000000000995c000 JavaThread "Thread-1842" [_thread_in_native, id=10632, stack(0x00000000146b0000,0x00000000147b0000)]
  0x0000000009959800 JavaThread "Thread-1841" [_thread_in_native, id=4240, stack(0x0000000015a80000,0x0000000015b80000)]
  0x0000000009958800 JavaThread "Thread-1828" [_thread_blocked, id=632, stack(0x00000000145b0000,0x00000000146b0000)]
  0x000000000995c800 JavaThread "Thread-1754" [_thread_in_native, id=11188, stack(0x0000000015980000,0x0000000015a80000)]
  0x0000000009957800 JavaThread "Thread-1699" [_thread_in_native, id=8788, stack(0x00000000144b0000,0x00000000145b0000)]
  0x000000000995a800 JavaThread "Thread-1650" [_thread_in_native, id=10860, stack(0x000000000fe20000,0x000000000ff20000)]
  0x00000000097bc000 JavaThread "Java Sound Sequencer" [_thread_blocked, id=11096, stack(0x0000000006cc0000,0x0000000006dc0000)]
  0x0000000009957000 JavaThread "Thread-1285" [_thread_in_native, id=10608, stack(0x00000000142b0000,0x00000000143b0000)]
  0x00000000097c3800 JavaThread "Thread-1223" [_thread_in_native, id=6968, stack(0x000000000eff0000,0x000000000f0f0000)]
  0x00000000097c9000 JavaThread "Thread-1157" [_thread_in_vm, id=9260, stack(0x00000000143b0000,0x00000000144b0000)]
  0x00000000097c0800 JavaThread "Thread-1139" [_thread_in_native, id=10544, stack(0x00000000141b0000,0x00000000142b0000)]
  0x00000000097ca800 JavaThread "Thread-1138" [_thread_in_native, id=8456, stack(0x00000000140b0000,0x00000000141b0000)]
  0x00000000097c6800 JavaThread "Thread-1113" [_thread_in_native, id=10536, stack(0x000000000fa20000,0x000000000fb20000)]
  0x00000000097c8800 JavaThread "Thread-1110" [_thread_in_native, id=7780, stack(0x000000000edf0000,0x000000000eef0000)]
  0x00000000097c5800 JavaThread "Thread-1054" [_thread_in_native, id=10472, stack(0x000000000eef0000,0x000000000eff0000)]
  0x00000000097c1800 JavaThread "Thread-1046" [_thread_in_native, id=6148, stack(0x0000000013fb0000,0x00000000140b0000)]
  0x00000000097c0000 JavaThread "Thread-1030" [_thread_in_native, id=10720, stack(0x000000000e3a0000,0x000000000e4a0000)]
  0x00000000097c8000 JavaThread "Thread-963" [_thread_in_native, id=3148, stack(0x000000000ac50000,0x000000000ad50000)]
  0x00000000097c2000 JavaThread "Thread-923" [_thread_in_native, id=10492, stack(0x000000000fd20000,0x000000000fe20000)]
  0x00000000097c7000 JavaThread "Thread-791" [_thread_in_native, id=2044, stack(0x000000000e5a0000,0x000000000e6a0000)]
  0x00000000097c2800 JavaThread "Thread-751" [_thread_in_native, id=2780, stack(0x000000000e4a0000,0x000000000e5a0000)]
=>0x00000000097c4000 JavaThread "Thread-651" [_thread_in_native, id=5524, stack(0x000000000ecf0000,0x000000000edf0000)]
  0x00000000097bf000 JavaThread "DestroyJavaVM" [_thread_blocked, id=10636, stack(0x0000000002370000,0x0000000002470000)]
  0x00000000097be800 JavaThread "D3D Screen Updater" daemon [_thread_blocked, id=10044, stack(0x000000000d940000,0x000000000da40000)]
  0x00000000097bd800 JavaThread "AWT-EventQueue-0" [_thread_blocked, id=3036, stack(0x000000000cc50000,0x000000000cd50000)]
  0x00000000097bd000 JavaThread "AWT-Shutdown" [_thread_blocked, id=10372, stack(0x000000000cb50000,0x000000000cc50000)]
  0x0000000009633800 JavaThread "TimerQueue" daemon [_thread_blocked, id=10840, stack(0x000000000b650000,0x000000000b750000)]
  0x0000000009631000 JavaThread "Headspace mixer frame proc thread" daemon [_thread_blocked, id=10808, stack(0x000000000ae50000,0x000000000af50000)]
  0x00000000095f0800 JavaThread "Java Sound Event Dispatcher" daemon [_thread_blocked, id=8628, stack(0x000000000a950000,0x000000000aa50000)]
  0x00000000062c1000 JavaThread "Java Sound Event Dispatcher" daemon [_thread_blocked, id=10864, stack(0x000000000a850000,0x000000000a950000)]
  0x000000000618c000 JavaThread "AWT-Windows" daemon [_thread_in_native, id=10984, stack(0x0000000006dc0000,0x0000000006ec0000)]
  0x0000000006189800 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=1848, stack(0x0000000006bc0000,0x0000000006cc0000)]
  0x0000000006145000 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=7160, stack(0x00000000066f0000,0x00000000067f0000)]
  0x000000000052d800 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=10604, stack(0x00000000065f0000,0x00000000066f0000)]
  0x0000000000526800 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=2820, stack(0x00000000064f0000,0x00000000065f0000)]
  0x0000000000524800 JavaThread "Attach Listener" daemon [_thread_blocked, id=1616, stack(0x00000000063f0000,0x00000000064f0000)]
  0x0000000000523800 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=9476, stack(0x00000000062f0000,0x00000000063f0000)]
  0x000000000050f800 JavaThread "Finalizer" daemon [_thread_blocked, id=9472, stack(0x0000000005ff0000,0x00000000060f0000)]
  0x0000000000506800 JavaThread "Reference Handler" daemon [_thread_blocked, id=8864, stack(0x0000000005ef0000,0x0000000005ff0000)]

Other Threads:
  0x00000000004fe000 VMThread [stack: 0x0000000005df0000,0x0000000005ef0000] [id=3480]
  0x0000000006160800 WatcherThread [stack: 0x00000000067f0000,0x00000000068f0000] [id=6728]

VM state:not at safepoint (normal execution)

VM Mutex/Monitor currently owned by a thread: None

Heap
 PSYoungGen      total 10240K, used 4696K [0x00000000ead60000, 0x00000000eb980000, 0x0000000100000000)
  eden space 10112K, 45% used [0x00000000ead60000,0x00000000eb1de278,0x00000000eb740000)
  from space 128K, 75% used [0x00000000eb770000,0x00000000eb788000,0x00000000eb790000)
  to   space 1152K, 0% used [0x00000000eb860000,0x00000000eb860000,0x00000000eb980000)
 PSOldGen        total 43392K, used 23839K [0x00000000c0800000, 0x00000000c3260000, 0x00000000ead60000)
  object space 43392K, 54% used [0x00000000c0800000,0x00000000c1f47f00,0x00000000c3260000)
 PSPermGen       total 21248K, used 12322K [0x00000000bb600000, 0x00000000bcac0000, 0x00000000c0800000)
  object space 21248K, 57% used [0x00000000bb600000,0x00000000bc208830,0x00000000bcac0000)

Code Cache  [0x0000000002470000, 0x00000000026f0000, 0x0000000005470000)
 total_blobs=1022 nmethods=599 adapters=376 free_code_cache=47801344 largest_free_block=16000

Dynamic libraries:
0x0000000000400000 - 0x000000000042e000     C:\Windows\system32\java.exe
0x00000000774b0000 - 0x0000000077659000     C:\Windows\SYSTEM32\ntdll.dll
0x0000000077020000 - 0x000000007713f000     C:\Windows\system32\kernel32.dll
0x000007fefda00000 - 0x000007fefda6c000     C:\Windows\system32\KERNELBASE.dll
0x000007feff4e0000 - 0x000007feff5bb000     C:\Windows\system32\ADVAPI32.dll
0x000007feff6a0000 - 0x000007feff73f000     C:\Windows\system32\msvcrt.dll
0x000007fefe490000 - 0x000007fefe4af000     C:\Windows\SYSTEM32\sechost.dll
0x000007fefe4b0000 - 0x000007fefe5dd000     C:\Windows\system32\RPCRT4.dll
0x000000006d7f0000 - 0x000000006dfa8000     C:\Program Files\Java\jre6\bin\server\jvm.dll
0x0000000076dd0000 - 0x0000000076eca000     C:\Windows\system32\USER32.dll
0x000007feff740000 - 0x000007feff7a7000     C:\Windows\system32\GDI32.dll
0x000007fefde60000 - 0x000007fefde6e000     C:\Windows\system32\LPK.dll
0x000007fefdd10000 - 0x000007fefddd9000     C:\Windows\system32\USP10.dll
0x000007fefb970000 - 0x000007fefb9ab000     C:\Windows\system32\WINMM.dll
0x000007fefdce0000 - 0x000007fefdd0e000     C:\Windows\system32\IMM32.DLL
0x000007fefe5e0000 - 0x000007fefe6e9000     C:\Windows\system32\MSCTF.dll
0x000000006d760000 - 0x000000006d76e000     C:\Program Files\Java\jre6\bin\verify.dll
0x000000006d3b0000 - 0x000000006d3d7000     C:\Program Files\Java\jre6\bin\java.dll
0x000000006d7b0000 - 0x000000006d7c2000     C:\Program Files\Java\jre6\bin\zip.dll
0x000000006d000000 - 0x000000006d1c3000     C:\Program Files\Java\jre6\bin\awt.dll
0x000007fefb9b0000 - 0x000007fefba21000     C:\Windows\system32\WINSPOOL.DRV
0x000007fefdf80000 - 0x000007fefe183000     C:\Windows\system32\ole32.dll
0x000007fefe750000 - 0x000007feff4d8000     C:\Windows\system32\SHELL32.dll
0x000007fefdde0000 - 0x000007fefde51000     C:\Windows\system32\SHLWAPI.dll
0x000007fefc3b0000 - 0x000007fefc5a4000     C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_fa396087175ac9ac\COMCTL32.dll
0x000007fefbd70000 - 0x000007fefbd88000     C:\Windows\system32\DWMAPI.DLL
0x000007fefc1d0000 - 0x000007fefc226000     C:\Windows\system32\uxtheme.dll
0x000000006d2a0000 - 0x000000006d306000     C:\Program Files\Java\jre6\bin\fontmanager.dll
0x000007fefd840000 - 0x000007fefd84f000     C:\Windows\system32\CRYPTBASE.dll
0x000007feee310000 - 0x000007feee50f000     C:\Windows\system32\d3d9.dll
0x000007fefca70000 - 0x000007fefca7c000     C:\Windows\system32\VERSION.dll
0x000007fefbad0000 - 0x000007fefbad7000     C:\Windows\system32\d3d8thk.dll
0x000007feea170000 - 0x000007feeaabb000     C:\Windows\system32\nvd3dumx.dll
0x000007fefbb00000 - 0x000007fefbb2c000     C:\Windows\system32\powrprof.dll
0x000007fefe210000 - 0x000007fefe3e7000     C:\Windows\system32\SETUPAPI.dll
0x000007fefd9c0000 - 0x000007fefd9f6000     C:\Windows\system32\CFGMGR32.dll
0x000007feff5c0000 - 0x000007feff697000     C:\Windows\system32\OLEAUT32.dll
0x000007fefdcc0000 - 0x000007fefdcda000     C:\Windows\system32\DEVOBJ.dll
0x000000006d510000 - 0x000000006d53e000     C:\Program Files\Java\jre6\bin\jsound.dll
0x000007fefbd90000 - 0x000007fefbddb000     C:\Windows\system32\MMDevAPI.DLL
0x000007fefc230000 - 0x000007fefc35c000     C:\Windows\system32\PROPSYS.dll
0x000007fef3590000 - 0x000007fef35cb000     C:\Windows\system32\wdmaud.drv
0x0000000074b10000 - 0x0000000074b16000     C:\Windows\system32\ksuser.dll
0x000007fefbea0000 - 0x000007fefbea9000     C:\Windows\system32\AVRT.dll
0x000007fefb5c0000 - 0x000007fefb60f000     C:\Windows\system32\AUDIOSES.DLL
0x000007fef40f0000 - 0x000007fef40fa000     C:\Windows\system32\msacm32.drv
0x000007fef40d0000 - 0x000007fef40e8000     C:\Windows\system32\MSACM32.dll
0x000007fef3580000 - 0x000007fef3589000     C:\Windows\system32\midimap.dll
0x000007fefe3f0000 - 0x000007fefe489000     C:\Windows\system32\CLBCatQ.DLL
0x0000000010000000 - 0x0000000010065000     C:\Program Files\WIDCOMM\Bluetooth Software\btmmhook.dll
0x0000000077670000 - 0x0000000077677000     C:\Windows\system32\PSAPI.DLL
0x000000006d600000 - 0x000000006d617000     C:\Program Files\Java\jre6\bin\net.dll
0x000007fefdf30000 - 0x000007fefdf7d000     C:\Windows\system32\WS2_32.dll
0x000007feff7b0000 - 0x000007feff7b8000     C:\Windows\system32\NSI.dll
0x000007fefd140000 - 0x000007fefd195000     C:\Windows\system32\mswsock.dll
0x000007fefd130000 - 0x000007fefd137000     C:\Windows\System32\wship6.dll
0x000000006d620000 - 0x000000006d62b000     C:\Program Files\Java\jre6\bin\nio.dll
0x0000000009540000 - 0x0000000009571000     C:\Program Files\WIDCOMM\Bluetooth Software\btkeyind.dll

VM Arguments:
java_command: MyGameMain
Launcher Type: SUN_STANDARD

Environment Variables:
CLASSPATH=.;C:\Program Files (x86)\Java\jre6\lib\ext\QTJava.zip
PATH=C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\PC Connectivity Solution\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Broadcom\Broadcom 802.11\Driver;C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\WIDCOMM\Bluetooth Software\syswow64;C:\Program Files\Java\jdk1.6.0_21\bin;C:\MinGW\bin;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Windows\system32\wbem;C:\Program Files (x86)\IVT Corporation\BlueSoleil\Mobile;c:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\Program Files\Common Files\Microsoft Shared\Windows Live
USERNAME=***********
OS=Windows_NT
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 23 Stepping 6, GenuineIntel



---------------  S Y S T E M  ---------------

OS: Windows 7 , 64 bit Build 7601 Service Pack 1

CPU:total 2 (2 cores per cpu, 1 threads per core) family 6 model 23 stepping 6, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1

Memory: 4k page, physical 4160724k(2268648k free), swap 8319600k(5448724k free)

vm_info: Java HotSpot(TM) 64-Bit Server VM (20.4-b02) for windows-amd64 JRE (1.6.0_29-b11), built on Oct  3 2011 01:06:42 by "java_re" with MS VC++ 8.0 (VS2005)

time: Sat Feb 04 09:25:56 2012
elapsed time: 145 seconds

日志文件表明,当声音完成并调用 SourceDataLine.drain() 以清除声音缓冲区中的任何剩余数据时,崩溃发生在声音线程期间。我不确定我做错了什么导致我的测试人员的 jre 在游戏中途崩溃......

您的声音/线程专家的任何见解都会有所帮助。

【问题讨论】:

有几个异常被捕获但未登录到 SoundThread。你确定这不是问题所在吗? 如需尽快获得更好的帮助,请发帖SSCCE。 Andrew:刚刚为它创建了一个 SSCCE。编辑了我的 OP 以提供它。 Jivings:我更改了那些 try-catch 块以打印异常消息。我正在等待我的测试人员查看异常(如果有)要说什么。 Jivings:我修改代码后,我的测试人员没有收到任何异常信息。它只是崩溃而不抛出异常。 【参考方案1】:

可能为时已晚,无法为您提供任何帮助,但以防万一其他人感兴趣 -

SoundThread::run 中,您正在检查bytesRead,但如果stream.read 返回zero(也许它不应该),那么您将陷入无限循环。

这可能取决于正在播放的声音的精确长度,并且可以解释为什么只有一个人能看到问题。

【讨论】:

【参考方案2】:

冒着因为没有直接回答你的问题而被骂的风险,我想提出一个建议。可以创建一个自定义“剪辑”对象,该对象允许多次播放和以不同速度播放。如果 ClipTrack(我的名字)有多个光标,它们的输出可以相加并作为单个音频值发送出去。

我在这里演示了这样的用法: ClipTrack

该站点上有指向 Java 代码的链接,发布在 Java-Gaming.org,欢迎您使用。但是您可能需要大量编辑源代码。我知道我从最初发布它开始。我只是一名中级 Java 程序员,并且正在自学声音。有很多事情应该以不同的方式完成(对象将数据“移交”到我编写的混音器而不是直接播放它 - 但你可以重写它,如果完全不使用 CopyOnWriteArrayList 也可能不是最佳的-可以设计管理游标的阻塞方法)。

但是,至少在那里可以看到基本的想法。 :)

这种方法的潜在好处包括减少线程数。此外,您一次在内存中永远不会有超过一份原始音频数据的副本(而不是在所有剪辑中制作多个副本)。

我发现使用 javax.sound Clips 非常烦人,我很高兴不再纠结于它们。

【讨论】:

你好菲尔。最初,我使用 Clips 播放声音,但大约一半的测试我的游戏的人遇到了 Clips 问题,导致游戏延迟。如果我不能让任何其他工作,我会给你的 ClipTrack 课程一个机会。在花时间学习一个全新的类包之前,我想知道是什么导致我当前的声音线程代码崩溃。【参考方案3】:

这是一个不同的答案,我不会修改之前关于编写自定义剪辑的建议(这是一种有效的方法,尽管方法非常不同)。

顺便说一句:我对 SourceDataLine 使用变量名“clip”感到困惑。真的应该重构那种东西!

好的。查看您的代码,您省略了我在播放重叠 SDL 的应用程序中包含的三个步骤。

line.drain();
line.stop();
line.close();
line = null;

aiStream.close();
aiStream = null;

其中“line”是 SourceDataLine,aiStream 是 AudioInputStream。

我认为将这些设置为 null 可能是关键步骤。不确定省略的 stop() 步骤有多重要。我无法确切告诉您为什么需要这样做,但它对我的应用程序产生了影响。

【讨论】:

我会让我的测试员试一试。 这并没有解决问题。 :( 我的测试人员说它仍然在崩溃。 感谢您告诉我。很抱歉,它没有帮助。【参考方案4】:

此问题仍未解决。总之,问题可能是发生问题的机器所固有的,并且可能不值得在本机 Java 中进一步研究。

【讨论】:

以上是关于Java多线程声音崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程-进程和线程概念

多线程并发会造成程序周期性崩溃吗?

Java-多线程框架Executor(下)

Java—多线程创建详解

安卓下多线程OpenGL共享Context

一个多线程问题的逻辑思考