将线程中的停止标志设置为真,线程为空?
Setting a stop flag in a thread to true, thread is null?
显然,我目前的方法不是应该如何完成,因为它不起作用。
我的项目是根据从网络服务器收到的时间表播放音频的软件。
我有三个线程,一个线程是一个侦听器,它在网络套接字上侦听有关是否有我们应该下载的新计划的通知。此线程启动另一个线程 "Schedule Downloader",这会发出 http 请求并下载文件。当它启动时,它会检查计划并下载文件,在它执行此操作后,一旦有一个标志设置为 false 并且标志上有一个 while 循环,所以线程仍然 运行 但在该标志被更改之前不做任何事情。这个标志是boolean newSchedule
。完成后,它会启动一个线程来播放音乐
我目前设置它的方式是我的侦听器 onMessage()
中的方法 MyTopicClass
更改计划下载器中的标志以再次开始下载计划。我可以从调试中看到这有效。接收通知会调用我的 ScheduleDownloader
class 中的 getScheduleAgain()
方法,该方法会更改标志并且我的代码会再次启动 checking/downloading 计划。我可以看到它正常工作。没有按我的意图工作的是我试图在我的 AudioPlayer
中设置一个标志,以便它完成,以便我可以使用新的时间表开始一个新的。出了什么问题是当我在我的 getScheduleAgain()
方法中调用我的音频播放器上的 setStopFlagToTrue()
时,根据调试器,音频播放器是 null
?
所以我的工作流程是 MyTopic
在我的 IotClient
侦听器线程中,当它收到通知时,它会在我的 myTopic
中调用 onMessage()
,它会调用我的 getScheduleAgain()
在我的 Scheduledownloader
中。这一切都按预期工作,除了我的 getScheduleAgain()
方法在我的音频播放器线程上调用 setStopFlagToTrue
但根据调试器它是 null
?
Main.java
IotClient client = new IotClient("username");
client.start();
物联网客户端
public class IotClient extends Thread {
Thread t;
String username;
ScheduleDownloader downloader;
public IotClient(String username) {
this.username = username;
downloader = new ScheduleDownloader("username,","password2","thread");
}
public void run(){
this.currentThread().setPriority(Thread.MAX_PRIORITY);
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
String clientEndpoint = "removed my end point here";
// replace <prefix> and <region> with your own
String clientId = "1"; // replace with your own client ID. Use unique client IDs for concurrent connections.
// AWS IAM credentials could be retrieved from AWS Cognito, STS, or other secure sources
AWSIotMqttClient client = new AWSIotMqttClient(clientEndpoint, clientId, "removed credentials ", "removed credentials");
// optional parameters can be set before connect()
try {
client.connect();
} catch (AWSIotException e) {
e.printStackTrace();
}
AWSIotQos qos = AWSIotQos.QOS0;
new ScheduleDownloader("dunnesdrogheda","password2","thread").start();
AWSIotTopic topic = new MyTopic("schedule/"+ username, qos,downloader);
try {
client.subscribe(topic, true);
} catch (AWSIotException e) {
e.printStackTrace();
}
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void start(){
if (t == null) {
t = new Thread (this, "IotClientThread");
t.start ();
}
}
}
我的主题
public class MyTopic extends AWSIotTopic {
ScheduleDownloader downloader;
public MyTopic(String topic, AWSIotQos qos, ScheduleDownloader downloader) {
super(topic, qos);
this.downloader = downloader;
}
@Override
public void onMessage(AWSIotMessage message) {
System.out.println("Message recieved from topic: "+ message.getStringPayload());
try {
downloader.getScheduleAgain();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ScheduleDownloader,删除了用于下载文件的不相关的 util 方法
public class ScheduleDownloader extends Thread {
private Thread t;
private String threadName;
String username;
String password;
volatile boolean newSchedule = true;
AudioPlayer audioPlayer;
public ScheduleDownloader(String username,String password,String threadName){
this.username = username;
this.password = password;
this.threadName= threadName;
}
public void startPlayerThread(){
}
public void startAudioPlayer(Schedule schedule) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
audioPlayer = new AudioPlayer(schedule);
audioPlayer.start();
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}}
public synchronized void run() {
try {
while(true){
Thread.sleep(1000);
while(newSchedule == true) {
Schedule schedule = null;
while (schedule == null) {
System.out.println("Searching for schedule");
schedule = getTodaysSchedule();
}
System.out.println("Schedule Found");
boolean result = false;
while (result == false) {
result = downloadFiles(schedule);
}
System.out.println("Files Downloaded");
startAudioPlayer(schedule);
newSchedule = false;
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void getScheduleAgain() throws InterruptedException {
this.audioPlayer.setStopFlagToTrue();
Thread.sleep(4000);
newSchedule = true;
}
AudioDownloader,checkShouldWePlayAnAdvertisement
是循环直到完成标志应该设置为 true
的方法
public class AudioPlayer extends Thread {
Long currentFrameMusic;
Long currentFrameAdvertisement;
Clip clipMusic;
Clip clipAdvertisement;
private Thread t;
private volatile boolean stopFlag = false;
// current status of clip
String statusMusic;
String statusAdvertisement;
static AudioInputStream musicInputStream;
static AudioInputStream advertisementInputStream;
static String filePath;
Schedule schedule;
// constructor to initialize streams and clip
public AudioPlayer(Schedule schedule)
throws UnsupportedAudioFileException,
IOException, LineUnavailableException
{
//setup audio stream for music first
// create AudioInputStream object
this.schedule = schedule;
appendMusicFiles(schedule);
// create clip reference
clipMusic = AudioSystem.getClip();
// open audioInputStream to the clip
clipMusic.open(musicInputStream);
clipMusic.loop(Clip.LOOP_CONTINUOUSLY);
}
public void run(){
playMusic();
try {
checkShouldWePlayAnAdvertisement();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
checkShouldWePlayAnAdvertisement();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
checkShouldWePlayAnAdvertisement();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start(){
t = new Thread (this, "AudioPlayerThread");
t.start ();
}
public void checkShouldWePlayAnAdvertisement() throws IOException, UnsupportedAudioFileException, LineUnavailableException, InterruptedException {
ArrayList<String> playedAtTimes = new ArrayList<>();
ArrayList<Advertisement> advertisementsToBePlayed = new ArrayList<>();
boolean found;
//played at times is used to keep track of what time we played advertisements
//so when the loop reruns and the time hasnt changed it doesnt play it again
while(stopFlag ==false){
Thread.sleep(1000);
found = false;
ZonedDateTime zdt = ZonedDateTime.now();
String timeHHMM =zdt.toString().substring(11,16);
for(int i =0;i<schedule.getAdvertisementScheduleItems().size();i++){
if(schedule.getAdvertisementScheduleItems().get(i).getTimes().contains(timeHHMM)){
//this item should be played now
if(playedAtTimes.contains(timeHHMM)){
//we already played this,but the time hasnt changed when the loop ran again
}else{
advertisementsToBePlayed.add(schedule.getAdvertisementScheduleItems().get(i).getAdvertisement());
found = true;
}
}
}
if(found== true) {
playedAtTimes.add(timeHHMM);
appendAdvertisementFiles(advertisementsToBePlayed);
pauseMusic();
playAdvertisements();
stopAdvertisement();
resumeAudioMusic();
}
}
System.out.println("audio player is closing");
clipMusic.close();
}
public synchronized void setStopFlagToTrue(){
stopFlag = true;
}
在 IotClient.java 中,您创建了两个 ScheduleDownloader 实例。
public IotClient(String username) {
this.username = username;
downloader = new ScheduleDownloader("username,", "password2", "thread");
}
new ScheduleDownloader("dunnesdrogheda", "password2", "thread").start();
AWSIotTopic topic = new MyTopic("schedule/" + username, qos, downloader);
并且您已将 1 个实例传递给 AWSIotTopic,并使用另一个实例通过 while(true)
生成线程
来自 MyTopic.java 的 ScheduleDownloader 实例甚至不知道 audioPlayer 并给出 nullPointerException。
尝试使用相同的 ScheduleDownloader 实例或将 audioPlayer 定义为 public static,它应该可以正常工作。
显然,我目前的方法不是应该如何完成,因为它不起作用。 我的项目是根据从网络服务器收到的时间表播放音频的软件。
我有三个线程,一个线程是一个侦听器,它在网络套接字上侦听有关是否有我们应该下载的新计划的通知。此线程启动另一个线程 "Schedule Downloader",这会发出 http 请求并下载文件。当它启动时,它会检查计划并下载文件,在它执行此操作后,一旦有一个标志设置为 false 并且标志上有一个 while 循环,所以线程仍然 运行 但在该标志被更改之前不做任何事情。这个标志是boolean newSchedule
。完成后,它会启动一个线程来播放音乐
我目前设置它的方式是我的侦听器 onMessage()
中的方法 MyTopicClass
更改计划下载器中的标志以再次开始下载计划。我可以从调试中看到这有效。接收通知会调用我的 ScheduleDownloader
class 中的 getScheduleAgain()
方法,该方法会更改标志并且我的代码会再次启动 checking/downloading 计划。我可以看到它正常工作。没有按我的意图工作的是我试图在我的 AudioPlayer
中设置一个标志,以便它完成,以便我可以使用新的时间表开始一个新的。出了什么问题是当我在我的 getScheduleAgain()
方法中调用我的音频播放器上的 setStopFlagToTrue()
时,根据调试器,音频播放器是 null
?
所以我的工作流程是 MyTopic
在我的 IotClient
侦听器线程中,当它收到通知时,它会在我的 myTopic
中调用 onMessage()
,它会调用我的 getScheduleAgain()
在我的 Scheduledownloader
中。这一切都按预期工作,除了我的 getScheduleAgain()
方法在我的音频播放器线程上调用 setStopFlagToTrue
但根据调试器它是 null
?
Main.java
IotClient client = new IotClient("username");
client.start();
物联网客户端
public class IotClient extends Thread {
Thread t;
String username;
ScheduleDownloader downloader;
public IotClient(String username) {
this.username = username;
downloader = new ScheduleDownloader("username,","password2","thread");
}
public void run(){
this.currentThread().setPriority(Thread.MAX_PRIORITY);
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
String clientEndpoint = "removed my end point here";
// replace <prefix> and <region> with your own
String clientId = "1"; // replace with your own client ID. Use unique client IDs for concurrent connections.
// AWS IAM credentials could be retrieved from AWS Cognito, STS, or other secure sources
AWSIotMqttClient client = new AWSIotMqttClient(clientEndpoint, clientId, "removed credentials ", "removed credentials");
// optional parameters can be set before connect()
try {
client.connect();
} catch (AWSIotException e) {
e.printStackTrace();
}
AWSIotQos qos = AWSIotQos.QOS0;
new ScheduleDownloader("dunnesdrogheda","password2","thread").start();
AWSIotTopic topic = new MyTopic("schedule/"+ username, qos,downloader);
try {
client.subscribe(topic, true);
} catch (AWSIotException e) {
e.printStackTrace();
}
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void start(){
if (t == null) {
t = new Thread (this, "IotClientThread");
t.start ();
}
}
}
我的主题
public class MyTopic extends AWSIotTopic {
ScheduleDownloader downloader;
public MyTopic(String topic, AWSIotQos qos, ScheduleDownloader downloader) {
super(topic, qos);
this.downloader = downloader;
}
@Override
public void onMessage(AWSIotMessage message) {
System.out.println("Message recieved from topic: "+ message.getStringPayload());
try {
downloader.getScheduleAgain();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ScheduleDownloader,删除了用于下载文件的不相关的 util 方法
public class ScheduleDownloader extends Thread {
private Thread t;
private String threadName;
String username;
String password;
volatile boolean newSchedule = true;
AudioPlayer audioPlayer;
public ScheduleDownloader(String username,String password,String threadName){
this.username = username;
this.password = password;
this.threadName= threadName;
}
public void startPlayerThread(){
}
public void startAudioPlayer(Schedule schedule) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
audioPlayer = new AudioPlayer(schedule);
audioPlayer.start();
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}}
public synchronized void run() {
try {
while(true){
Thread.sleep(1000);
while(newSchedule == true) {
Schedule schedule = null;
while (schedule == null) {
System.out.println("Searching for schedule");
schedule = getTodaysSchedule();
}
System.out.println("Schedule Found");
boolean result = false;
while (result == false) {
result = downloadFiles(schedule);
}
System.out.println("Files Downloaded");
startAudioPlayer(schedule);
newSchedule = false;
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void getScheduleAgain() throws InterruptedException {
this.audioPlayer.setStopFlagToTrue();
Thread.sleep(4000);
newSchedule = true;
}
AudioDownloader,checkShouldWePlayAnAdvertisement
是循环直到完成标志应该设置为 true
public class AudioPlayer extends Thread {
Long currentFrameMusic;
Long currentFrameAdvertisement;
Clip clipMusic;
Clip clipAdvertisement;
private Thread t;
private volatile boolean stopFlag = false;
// current status of clip
String statusMusic;
String statusAdvertisement;
static AudioInputStream musicInputStream;
static AudioInputStream advertisementInputStream;
static String filePath;
Schedule schedule;
// constructor to initialize streams and clip
public AudioPlayer(Schedule schedule)
throws UnsupportedAudioFileException,
IOException, LineUnavailableException
{
//setup audio stream for music first
// create AudioInputStream object
this.schedule = schedule;
appendMusicFiles(schedule);
// create clip reference
clipMusic = AudioSystem.getClip();
// open audioInputStream to the clip
clipMusic.open(musicInputStream);
clipMusic.loop(Clip.LOOP_CONTINUOUSLY);
}
public void run(){
playMusic();
try {
checkShouldWePlayAnAdvertisement();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
checkShouldWePlayAnAdvertisement();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
checkShouldWePlayAnAdvertisement();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start(){
t = new Thread (this, "AudioPlayerThread");
t.start ();
}
public void checkShouldWePlayAnAdvertisement() throws IOException, UnsupportedAudioFileException, LineUnavailableException, InterruptedException {
ArrayList<String> playedAtTimes = new ArrayList<>();
ArrayList<Advertisement> advertisementsToBePlayed = new ArrayList<>();
boolean found;
//played at times is used to keep track of what time we played advertisements
//so when the loop reruns and the time hasnt changed it doesnt play it again
while(stopFlag ==false){
Thread.sleep(1000);
found = false;
ZonedDateTime zdt = ZonedDateTime.now();
String timeHHMM =zdt.toString().substring(11,16);
for(int i =0;i<schedule.getAdvertisementScheduleItems().size();i++){
if(schedule.getAdvertisementScheduleItems().get(i).getTimes().contains(timeHHMM)){
//this item should be played now
if(playedAtTimes.contains(timeHHMM)){
//we already played this,but the time hasnt changed when the loop ran again
}else{
advertisementsToBePlayed.add(schedule.getAdvertisementScheduleItems().get(i).getAdvertisement());
found = true;
}
}
}
if(found== true) {
playedAtTimes.add(timeHHMM);
appendAdvertisementFiles(advertisementsToBePlayed);
pauseMusic();
playAdvertisements();
stopAdvertisement();
resumeAudioMusic();
}
}
System.out.println("audio player is closing");
clipMusic.close();
}
public synchronized void setStopFlagToTrue(){
stopFlag = true;
}
在 IotClient.java 中,您创建了两个 ScheduleDownloader 实例。
public IotClient(String username) {
this.username = username;
downloader = new ScheduleDownloader("username,", "password2", "thread");
}
new ScheduleDownloader("dunnesdrogheda", "password2", "thread").start();
AWSIotTopic topic = new MyTopic("schedule/" + username, qos, downloader);
并且您已将 1 个实例传递给 AWSIotTopic,并使用另一个实例通过 while(true)
生成线程来自 MyTopic.java 的 ScheduleDownloader 实例甚至不知道 audioPlayer 并给出 nullPointerException。
尝试使用相同的 ScheduleDownloader 实例或将 audioPlayer 定义为 public static,它应该可以正常工作。