gpt4 book ai didi

java - Java中如何终止匿名线程

转载 作者:行者123 更新时间:2023-11-30 11:11:50 24 4
gpt4 key购买 nike

这款战舰游戏是我尝试编写的第一个多线程应用程序,在我添加仅用于音效的多线程之前,它一直运行良好。所有这些都在一个类中,即 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com