- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这款战舰游戏是我尝试编写的第一个多线程应用程序,在我添加仅用于音效的多线程之前,它一直运行良好。所有这些都在一个类中,即 AudioManager。
我很确定我只是缺乏关于并发的经验和/或理解,即使我已经阅读了 Java 教程等。我认为我只需要一点帮助来让它点击。
无论如何,游戏运行良好,直到播放了足够多的声音以至于内存不足并给我这个错误:
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: unable to create new native thread
我正在为每个要播放的音效创建一个新线程,因为我不想让图形用户界面等待声音结束,而且因为声音经常彼此非常接近地播放,我不希望它们如果它们重叠,则在同一线程上发生冲突。我认为,问题在于我不确定如何在播放完声音后关闭每个线程而不会使主线程停止。
这是包含所有声音代码的类。使用 setSound() 方法播放声音,该方法设置要播放的声音,然后使用 Runnable 的 SoundPlayer 内部类启动一个新线程。提前致谢:
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
public class AudioManager {
private static Thread backgroundThread = new Thread();
private static int loopCounter = 2;
private static Clip clip;
private static String[] backgroundFiles = {
"/40_Avalon.wav","/13_Glatisant.wav",
"/31_Lying_In_Deceit.wav","/43_Return_to_Base.wav"};
private static String[] files = {
"/bigboom.wav","/Robot_blip.wav",
"/battleStations.WAV","/beep1.wav",
"/button-47.wav","/button-35.wav",
"/beep-23.wav","/Sonar_pings.wav",
"/button-21.wav","/SONAR.WAV"};
private static AudioInputStream currentBackgroundMusic;
private static AudioInputStream currentSound;
private static boolean backgroundOn = false;
private static boolean canStart = true;
private static AudioInputStream loadSound(int s){
AudioInputStream stream = null;
try {
stream = AudioSystem.getAudioInputStream(AudioManager.class.getClass().getResource(files[s]));
} catch (UnsupportedAudioFileException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stream;
}
private static AudioInputStream loadBackground(int s){
AudioInputStream stream = null;
try {
stream = AudioSystem.getAudioInputStream(AudioManager.class.getClass().getResource(backgroundFiles[s]));
} catch (UnsupportedAudioFileException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stream;
}
public static void setSound(int s){
currentSound = loadSound(s);
Thread thread = new Thread(new SoundPlayer());
thread.start();
}
private static void continueMusic(){
setBackgroundMusic(loopCounter);
loopCounter++;
if(loopCounter > 3) loopCounter = 0;
}
public static void playSound(){
try {
clip = AudioSystem.getClip();
clip.open(currentSound);
} catch (LineUnavailableException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clip.start();
}
public static void setBackgroundMusic(int s){
if (backgroundOn) {
backgroundOn = false;
canStart = false;
try {
backgroundThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
currentBackgroundMusic = loadBackground(s);
backgroundThread = new Thread(new MusicPlayer());
backgroundOn = true;
backgroundThread.start();
canStart = true;
}
private static void playSound2(AudioInputStream audio) {
AudioFormat audioFormat = audio.getFormat();
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,audioFormat);
try{
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
}
catch (Exception e)
{
e.printStackTrace();
}
line.start();
int nBytesRead = 0;
byte[] abData = new byte[128000];
while (nBytesRead != -1 && backgroundOn)
{
try{
nBytesRead = audio.read(abData, 0, abData.length);
} catch (IOException e){
e.printStackTrace();
}
if (nBytesRead == -1) break;
line.write(abData, 0, nBytesRead);
}
line.drain();
line.stop();
line.close();
line = null;
backgroundOn = false;
}
private static class MusicPlayer implements Runnable{
@Override
public void run() {
playSound2(currentBackgroundMusic);
}
}
private static class SoundPlayer implements Runnable{
@Override
public void run() {
playSound();
}
}
public static void loopMusic(){
Thread loop = new Thread(new Runnable(){
@Override
public void run() {
while(true){
if(backgroundThread.isAlive()){
try {
backgroundThread.join(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (canStart){
continueMusic();
}
}
}});
loop.start();
}
public static void reset(){
loopCounter = 2;
}
}
最佳答案
首先感谢所有发布答案的人。你们都提供了很多帮助,解决方案是您的答案的组合。为了其他可能有相同问题的人的利益,我决定发布我自己的答案和我想出的解决方案。
事实证明,我确实创建了太多线程,操作系统只让Java有一定的内存空间。所以我通过使用 ExecutorService 解决了这个问题。
但是,我仍然遇到同样的问题,即使我没有明确地创建大量新线程。为什么?因为我正在创建新的剪辑来播放声音。
我认为 Clips 以某种方式创建线程来播放声音,因此它们可以在不锁定程序或 GUI 的情况下播放(我以前不明白)。所以,为了一劳永逸地解决这个问题,并让我的游戏连续快速地播放完全相同的声音而无需剪辑或不必等待前一个声音结束,我摆脱了执行者并创建了十个剪辑每个声音,仅此而已。
播放声音时,它会增加一个索引,以便下次播放该声音时,它实际上会使用不同的剪辑(但加载了完全相同的声音),并准备播放下一个剪辑。
我的游戏不再创建过多线程或剪辑并且运行良好!下面是更新后的代码,以及我用来了解发生了什么的一些测试:
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
public class AudioManager {
private static ExecutorService backgroundPool = Executors.newFixedThreadPool(1);
private static Future<?> backgroundStatus;
private static int loopCounter = 2;
private static String[] backgroundFiles = {
"/40_Avalon.wav","/13_Glatisant.wav",
"/31_Lying_In_Deceit.wav","/43_Return_to_Base.wav"};
private static String[] files = {
"/bigboom.wav","/Robot_blip.wav",
"/battleStations.WAV","/beep1.wav",
"/button-47.wav","/button-35.wav",
"/beep-23.wav","/Sonar_pings.wav",
"/button-21.wav","/SONAR.WAV"};
private static AudioInputStream currentBackgroundMusic;
private static boolean backgroundOn = false;
private static boolean canStart = true;
private static int[] clipIndex = new int[10];
private static Clip[][] clips = new Clip[10][10];
private static void initializeClips(int sound){
clipIndex[sound] = 0;
for (int i = 0 ; i < 10 ; i++)
try {
clips[sound][i] = AudioSystem.getClip();
clips[sound][i].open(loadSound(sound));
clips[sound][i].addLineListener(new LineListener(){
@Override
public void update(LineEvent event) {
if(event.getType() == javax.sound.sampled.LineEvent.Type.STOP){
clips[sound][clipIndex[sound]].setFramePosition(0);
}
}});
} catch (LineUnavailableException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static AudioInputStream loadSound(int s){
AudioInputStream stream = null;
try {
stream = AudioSystem.getAudioInputStream(AudioManager.class.getClass().getResource(files[s]));
} catch (UnsupportedAudioFileException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stream;
}
private static AudioInputStream loadBackground(int s){
AudioInputStream stream = null;
try {
stream = AudioSystem.getAudioInputStream(AudioManager.class.getClass().getResource(backgroundFiles[s]));
} catch (UnsupportedAudioFileException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stream;
}
public static void setSound(int s){
if(clips[s] == null){
initializeClips(s);
}
playSound(s);
}
private static void continueMusic(){
setBackgroundMusic(loopCounter);
loopCounter++;
if(loopCounter > 3) loopCounter = 0;
}
public static void playSound(int sound){
if(clips[sound][0] == null){
initializeClips(sound);
}
clips[sound][clipIndex[sound]].start();
clipIndex[sound]++;
if(clipIndex[sound] == 10){
clipIndex[sound] = 0;
}
clips[sound][clipIndex[sound]].drain();
clips[sound][clipIndex[sound]].flush();
clips[sound][clipIndex[sound]].setFramePosition(0);
}
public static void setBackgroundMusic(int s){
canStart = false;
if (backgroundOn) {
backgroundOn = false;
}
currentBackgroundMusic = loadBackground(s);
backgroundStatus = backgroundPool.submit(new MusicPlayer());
canStart = true;
}
private static void playSound2(AudioInputStream audio) {
backgroundOn = true;
AudioFormat audioFormat = audio.getFormat();
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,audioFormat);
try{
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
}
catch (Exception e)
{
e.printStackTrace();
}
line.start();
int nBytesRead = 0;
byte[] abData = new byte[128000];
while (nBytesRead != -1 && backgroundOn){
try{
nBytesRead = audio.read(abData, 0, abData.length);
} catch (IOException e){
e.printStackTrace();
}
if (nBytesRead == -1) break;
line.write(abData, 0, nBytesRead);
}
line.drain();
line.stop();
line.close();
line = null;
backgroundOn = false;
}
private static class MusicPlayer implements Runnable{
@Override
public void run() {
playSound2(currentBackgroundMusic);
}
}
public static void loopMusic(){
Thread loop = new Thread(new Runnable(){
@Override
public void run() {
while(true){
if(backgroundStatus.isDone() && canStart){
continueMusic();
}
}
}});
loop.start();
}
public static void reset(){
loopCounter = 2;
}
}
下面的测试将告诉您您的操作系统允许 JVM 创建多少线程。收到错误后,只需查看打印到控制台的最后一个数字。
public class Test1 {
static long count = 0L;
public static void main(String[] args) {
while(true){
count ++;
System.out.println(count);
new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}).start();
}
}
}
下面是做同样事情的测试,除了创建剪辑和打开资源。请注意,剪辑本身不需要线程,但一旦您打开它们,它们就需要了。在每次测试错误之前,您应该得到相同的数字(或接近)。当然,您必须提供自己的声音文件才能运行第二个。
import java.io.IOException;
import java.util.ArrayList;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import audio.AudioManager;
public class Test2 {
static long count = 0L;
static ArrayList<Clip> clips = new ArrayList<>();
public static void main(String[] args) {
while(true){
count ++;
System.out.println(count);
try {
Clip clip1 = AudioSystem.getClip();
clip1.open(loadSound());
clips.add(clip1);
} catch (LineUnavailableException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static AudioInputStream loadSound(){
AudioInputStream stream = null;
try {
stream = AudioSystem.getAudioInputStream(AudioManager.class.getClass().getResource("/bigboom.wav"));
} catch (UnsupportedAudioFileException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stream;
}
}
关于java - Java中如何终止匿名线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27208568/
如果我终止应用程序,我在尝试保持我的功能运行时卡住了。 是否可以在应用程序未运行时保持核心位置(地理围栏/地理定位)和核心蓝牙运行?如果可能如何解决我的问题?我已经检查了背景模式,并实现了核心定位方法
该程序要求用户输入一个数字,然后从列表中返回详细信息。我该怎么做? do { Scanner in = new Scanner(System.in);
我正在开发一个内部分发的 iOS 应用程序(即,没有应用程序商店),我希望能够以恒定的 10 分钟间隔报告设备的位置。 无论如何,我在我的 plist 中包含了 location 作为字段 UIBac
我的 mongodb 服务器突然收到信号 15(终止)。我不知道为什么 mongodb 崩溃了。以下是日志消息。 Mon Jun 27 07:33:31.701 [signalProcessingTh
我按顺序运行了一堆malloc,并且每次都检查以确保它是成功的。像这样: typedef struct { int *aray; char *string; } mystruct; m
这个问题已经有答案了: How to stop a running pthread thread? (4 个回答) 已关闭 8 年前。 可以使用 pthread_join() 停止线程。但让我们想象一
#include #include #include struct node{ char data; int p; struct node *ptr; }; struct node *st
这个问题已经有答案了: Why should I use a semicolon after every function in javascript? (9 个回答) 已关闭 8 年前。 好吧,我问
我有一个启动多个工作线程的函数。每个工作线程都由一个对象封装,该对象的析构函数将尝试加入线程,即调用if (thrd_.joinable()) thrd_.join();。但是,每个 worker 必
我正在实现一个应用程序,当用户摇动手机时,该应用程序会监听并采取行动。 所以我实现了以下服务: public class ShakeMonitorService extends Service {
我在使用 Xcode 时遇到问题,其中弹出错误“Source Kit Service Terminated”,并且所有语法突出显示和代码完成在 Swift 中都消失了。我怎样才能解决这个问题? 这是一
我想为我的控制台应用程序安全退出,该应用程序将使用单声道在 linux 上运行,但我找不到解决方案来检测信号是否发送到它或用户是否按下了 ctrl+c。 在 Windows 上有内核函数 SetCon
关键: pthread_cancel函数发送终止信号pthread_setcancelstate函数设置终止方式pthread_testcancel函数取消线程(另一功能是:设置取消点) 1 线程取消
下面的程序在不同的选项级别下有不同的行为。当我用 -O3 编译它时,它永远不会终止。当我用 -O0 编译它时,它总是很快就会终止。 #include #include void *f(void *
我有 3 个节点的 K8S 集群,我创建了 3 个副本 pod,应用程序 app1 在所有 pod 上运行,我通过运行 service yaml 文件建立了服务,我可以看到通过运行 kubectl g
我打算使用 nginx 来代理 websocket。在执行 nginx reload/HUP 时,我知道 nginx 等待旧的工作进程停止处理所有请求。然而,在 websocket 连接中,这可能不会
在 Ubuntu 9.10 上使用 PVM 3.4.5-12(使用 apt-get 时的 PVM 包) 添加主机后程序终止。 laptop> pvm pvm> add bowtie-slave add
我编写了一个应用程序来从 iPhone 录制视频。它工作正常,但有一个大问题。当 AVCaptureSession 开始运行并且用户尝试从其库(iPod)播放音频时。此操作将使 AVCaptureSe
我将如何使用NSRunningApplication?我有与启动应用程序相反的东西: [[NSWorkspace sharedWorkspace] launchApplication:appName]
我正在使用 NSTask 执行一系列长时间运行的命令,如下所示: commandToRun = @"command 1;command2"; NSArray *arguments = [NSArray
我是一名优秀的程序员,十分优秀!