Java 将线程中的停止标志设置为true,线程是否为null?

Java 将线程中的停止标志设置为true,线程是否为null?,java,multithreading,iot,Java,Multithreading,Iot,很明显,我目前的方法不是应该怎么做,因为它不起作用。 我的项目是根据从web服务器接收的时间表播放音频的软件 我有三个线程,一个线程是一个侦听器,它在web套接字上侦听关于是否应该下载新计划的通知。这个线程启动另一个线程,它是一个“Schedule Downloader”,它发出http请求并下载文件。当它启动时,它会检查计划并下载文件,执行此操作后,会有一个标志设置为false,带有while循环on标志,因此线程仍在运行,但在该标志更改之前不会执行任何操作。此标志为boolean newSc

很明显,我目前的方法不是应该怎么做,因为它不起作用。 我的项目是根据从web服务器接收的时间表播放音频的软件

我有三个线程,一个线程是一个侦听器,它在web套接字上侦听关于是否应该下载新计划的通知。这个线程启动另一个线程,它是一个“Schedule Downloader”,它发出http请求并下载文件。当它启动时,它会检查计划并下载文件,执行此操作后,会有一个标志设置为false,带有while循环on标志,因此线程仍在运行,但在该标志更改之前不会执行任何操作。此标志为
boolean newSchedule
。完成后,它会启动一个线程来播放音乐

我当前设置它的方式是,我的侦听器
MyTopicClass
中的方法
onMessage()
更改计划下载程序中的标志,以再次开始下载计划。我可以从调试中看出这是可行的。接收到通知将调用my
ScheduleDownloader
类中的
GetScheduleReach()
方法,该方法将更改标志,my code将再次开始检查/下载计划。我看这是正确的。我的
AudioPlayer
中设置了一个标志,这样它就可以结束了,这样我就可以按照新的时间表开始一个新的播放了。问题是,当我在
getScheduleReach()
方法中调用音频播放器上的
setStopFlagtorue()
时,根据调试器,音频播放器为
null

因此,我的工作流是我的
IotClient
侦听器线程中的
MyTopic
,当它收到通知时,它在我的
MyTopic
中调用
onMessage()
,在我的
Scheduledownloader
中调用我的
getscheduleach()
。除了我的
getScheduleReach()
方法在我的audioplayer线程上调用
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 ();
}
}


  }
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,
复选框shouldWeplayanAdvertising
是一种循环方法,直到finish标志设置为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;
}
公共类AudioPlayer扩展线程{
悠长的音乐;
长期广告;
剪辑剪辑音乐;
剪贴画;
私有线程t;
私有易失性布尔stopFlag=false;
//clip的当前状态
弦乐;
字符串状态广告;
静态音频输入流音乐输入流;
静态音频输入流广告输入流;
静态字符串文件路径;
时间表;
//构造函数初始化流和剪辑
公共音频播放器(时间表)
抛出不支持的DaudioFileException,
IOException,LineUnavailableException
{
//首先设置音乐的音频流
//创建AudioInputStream对象
这个。时间表=时间表;
附件(附表);
//创建剪辑引用
clipMusic=AudioSystem.getClip();
//打开音频输入流到剪辑
clipMusic.open(musicInputStream);
clipMusic.loop(连续Clip.loop_);
}
公开募捐{
播放音乐();
试一试{
选中应播放广告();
}捕获(IOE异常){
e、 printStackTrace();
}捕获(不支持的数据文件异常e){
e、 printStackTrace();
}捕获(LineUnavailableException e){
e、 printStackTrace();
}捕捉(中断异常e){
e、 printStackTrace();
}
试一试{
选中应播放广告();
}捕获(IOE异常){
e、 printStackTrace();
}捕获(不支持的数据文件异常e){
e、 printStackTrace();
}捕获(LineUnavailableException e){
e、 printStackTrace();
}捕捉(中断异常e){
e、 printStackTrace();
}
试一试{
选中应播放广告();
}捕获(IOE异常){
e、 printStackTrace();
}捕获(不支持的数据文件异常e){
e、 printStackTrace();
}捕获(LineUnavailableException e){
e、 printStackTrace();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
公开作废开始(){
t=新线程(此为“AudioPlayerThread”);
t、 开始();
}
public void checkshouldWeplayanAdvertision()引发IOException、UnsupportdAudioFileException、LineUnavailableException、InterruptedException{
ArrayList playedAtTimes=新建ArrayList();
ArrayList advertisementsToBePlayed=新建ArrayList();
布尔发现;
//播放时间用于跟踪我们播放广告的时间
//因此,当循环重新运行且时间未更改时,它不会再次播放
while(stopFlag==false){
睡眠(1000);
发现=错误;
ZonedDateTime zdt=ZonedDateTime.now();
字符串timeHHMM=zdt.toString().substring(11,16);

对于IotClient.java中的(int i=0;i,您已经创建了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,应该可以正常工作。

您是否尝试过将ScheduleDownloader中的
audioPlayer
字段设置为volatile still?其他线程可能永远看不到该字段,除非
null
。将ScheduleDownloader中的audioPlayer设置为volatile still当在GetScheduleReach()中调用此.audioplayer.SetStopFlagtorue();时,会导致一个空audioplayer。我认为您还没有解释在尚未初始化音频播放器时首次出现的问题。老实说,我认为您需要
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);