简体   繁体   中英

Setting a stop flag in a thread to true, thread is null?

Obviously my current approach isn't how it should be done as it isn't working. My project is software that plays audio based on a schedule received from a web server.

I have three threads, one thread is a listener which listens on a web socket for notifications about whether there is a new schedule we should download. This thread starts another thread which is a "Schedule Downloader", this makes http requests and downloads files. When it starts it checks the schedule and downloads files, after it does this once there is a flag set to false with a while loop on flag, so the thread is still running but not doing anything until that flag is changed. This flag is boolean newSchedule . When it is finished it starts a thread to play the music

The way I currently have it setup is that my method onMessage() in my listener MyTopicClass changes a flag in the schedule downloader to start downloading a schedule again. I can see this works from debugging. Receiving a notification calls the getScheduleAgain() method in my ScheduleDownloader class which changes the flag and my code starts checking/downloading schedules again. I can see this works correctly. What doesn't work as I intend is I am trying to set a flag in my AudioPlayer so it finishes so I can start a new one with the new schedule. What is going wrong is when I call the setStopFlagToTrue() on my audio player inside my getScheduleAgain() method, according to the debugger the audioplayer is null ?

So my workflow is MyTopic within my IotClient listener thread when it receives a notification, it calls onMessage() in my myTopic which calls my getScheduleAgain() in my Scheduledownloader . This all works as intended except my getScheduleAgain() method calls a setStopFlagToTrue on my audioplayer thread but according to the debugger it is null ?

Main.java

      IotClient client = new IotClient("username");
  client.start();

IotClient

     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 ();
}
}


  }

MyTopic

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, removed non-relevant util methods for downloading files

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, the checkShouldWePlayAnAdvertisement is the method that loops until the finish flag is supposed to be set to 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;
}

In IotClient.java, You have created two instances of 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); 

And you have passed 1 instance to AWSIotTopic and used another to spawn the thread with while(true)

The ScheduleDownloader's instance from MyTopic.java doesn't even know about audioPlayer and gives nullPointerException.

Try using same instance of ScheduleDownloader OR define audioPlayer to public static and it should work fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM