I just started using the Jlayer library to play MP3s. It works perfectly and I can play the song. My only problem is implementing pause and resume methods. With my limited amount of knowledge about multithreading, I though that making the thread where I play the MP3 wait, the sound would stop and in order to resume the song I would just have to notify the thread. Here is what I got:
import java.util.Scanner;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import javazoom.jl.player.Player;
public class MP3 extends Thread{
private String filename;
private Player player;
private Thread t;
private volatile boolean continuePlaying = true;
// constructor that takes the name of an MP3 file
public MP3(String filename) {
this.filename = filename;
}
public void close() { if (player != null) player.close(); }
// play the MP3 file to the sound card
public void play() {
try {
FileInputStream fis = new FileInputStream(filename);
BufferedInputStream bis = new BufferedInputStream(fis);
player = new Player(bis);
}
catch (Exception e) {
System.out.println("Problem playing file " + filename);
System.out.println(e);
}
}
public void run() {
play();
try {
while (true) {
synchronized(this) {
while(!continuePlaying)
wait();
player.play();
}
}
}
catch (Exception e) {
System.out.println(e);
}
}
private void pause() throws InterruptedException{
System.out.println("Pause");
continuePlaying = false;
}
private void resumeSong() throws InterruptedException{
synchronized(this) {
System.out.println("Resume");
continuePlaying = true;
notify();
}
}
// test client
public static void main(String[] args) throws InterruptedException{
String filename = ("Fall To Pieces.mp3");
MP3 mp3 = new MP3(filename);
mp3.start();
Scanner s = new Scanner(System.in);
s.nextLine();
mp3.pause();
s.nextLine();
mp3.resumeSong();
try {
mp3.join();
} catch (Exception e){
}
}
}
For some reason, however, wait() doesn't do anything and the program doesn't even reach notify(). Why is this happening?
I've read the previous SO questions about this, but I haven't been able to make them work. I am also interested in learning why this code doesn't work so I can further understand multithreading. Thank you!
It's late here so pardon me if I read your code wrong. But as far as I see it, you start your thread with continuePlaying = true; and the run method just calls play(); no initialize the new player and then straight enters a while (true) loop wich has to exit point. continuePlaying can't be changed by that thread still stuck in it's endless loop and even if you start another MP3 thread to access the volatile variable, it will enter the same loop before being able to change anything. Therefore wait() will never be reached.
Later on you are trying to notify() your waiting thread from within itself. Which is a bit of a paradoxon because it is waiting to be notified and in that state of waiting doing nothing, let alone notifying itself. It simply can't do anything until notified, that includes notifying itself or others. What I am trying to say is, that you should handle wait() but especially notify() from outside the thread that is being adressed/waiting.
Additionally your player.play(); is in an odd position. At the moment the player should only start playing after the thread has been paused(waited) at least once because it is behind the while(!continuePlaying) condition.
So for your case i'd rater go with methods in a different thread (or even the main thread for your tests) which call a wait() and notify() on and synchronized over the thread in question.
Related
I am trying to make a text to speech thread stop whenever the talk(String text, boolean voiceEnabled) method is called from an ActionEvent using buttons.
When these buttons are pressed different text Strings are passed to the method, which runs the audio on a new thread. If the current thread is still running but a new ActionEvent occurs I need the current thread to stop (i.e the text-to-speech) so that the new text-to-speech audio can be played without the current audio clip and new clip playing over the top of eachother.
This is what I currently have but the TTS audio are playing over the top of eachother. I need the current TTS to stop as soon as a new TTS is triggered. I believe my main problem is that a new Thread is being made each time the method is called.
Any help greatly appreciated. Thanks!
public void talk(String text, boolean voiceEnabled) {
System.out.println(text);
// Create a new Thread as JLayer is running on the current Thread and will
// make the application lag
Thread thread = new Thread(() -> {
try {
// Create a JLayer instance
AdvancedPlayer player = new AdvancedPlayer(synthesizer.getMP3Data(text));
if (voiceEnabled) {
player.play(); //Plays the TTS audio
System.out.println("Successfully retrieved synthesizer data");
}
else {
}
} catch (IOException | JavaLayerException e) {
e.printStackTrace();
}
});
// We don't want the application to terminate before this Thread terminates
thread.setDaemon(false);
// Start the Thread
thread.start();
}
You appear to be burying key references inside of anonymous inner classes, and I don't see how you can get to them when and if needed. Why do this? Why not create an instance of a non-anonymous class, one with an AdvancedPlayer field, one whose reference is held by some collection, perhaps a List<...> or a HashMap, or by a variable if only one to two are running, where you can extract the object, get its AdvancedPlayer field and call .stop() on it?
e.g.,
public class RunnablePlayer implements Runnable {
private AdvancedPlayer player;
private String text;
private boolean voiceEnabled;
public RunnablePlayer(String text, boolean voiceEnabled) {
this.text = text;
this.voiceEnabled = voiceEnabled;
}
#Override
public void run() {
try {
// Create a JLayer instance
player = new AdvancedPlayer(synthesizer.getMP3Data(text));
if (voiceEnabled) {
player.play(); //Plays the TTS audio
System.out.println("Successfully retrieved synthesizer data");
}
} catch (IOException | JavaLayerException e) {
e.printStackTrace();
}
}
public AdvancedPlayer getPlayer() {
return player;
}
public void stop() {
// perhaps do a null check here first?
if (player != null) {
player.stop();
}
}
}
Then you could have a field of the class, something like:
// field of the class
private RunnablePlayer runnablePlayer;
and use this in your talk method:
public void talk(String text, boolean voiceEnabled) {
if (runnablePlayer != null) {
runnablePlayer.stop(); // not calling this on a Thread
}
runnablePlayer = new RunnablePlayer(text, voiceEnabled);
Thread thread = new Thread(runnablePlayer);
//.....
thread.start();
}
Code not compiled or tested, but is presented to just give a general idea.
Due to the fact that in almost every question regarding the use of Thread.sleep it is mostly indicated to use it only in certain situations, I come to ask you if it is correct to use it in my case or if there is a better way to do it.
The operating system is Linux(Debian), in which a bash script is running that is detecting when a device (more specifically, a storage device) is inserted/removed, and then writes into a FIFO a string under the type "ADD {path-to-dev}" or "REM {path-to-dev}".
I created a small app in java which makes use of two threads. The first thread will call upon a read method that parses the String to the standard output, after which it will wait(). The second thread will check if the FIFO is empty or not and then, when it sees that a String has been inserted then it will call notify() so the other thread will print the String in there and so on. Inside the loop where it checks if the FIFO has data or not, I call Thread.sleep(1000), and I am unsure whether this is a good approach or not. I will present the code which handles all the action.
First, the class which has the methods of reading:
public class Detect {
private File file;
private BufferedReader read;
private volatile boolean readable;
private static String readFromFile;
public Detect() throws FileNotFoundException {
file = new File("/hardware_stuff/hardware_events");
read = new BufferedReader(new FileReader(file));
readable = true;
}
synchronized String readFromFifo() {
while (!readable) {
try {
wait();
} catch (InterruptedException ex) {
System.out.println("Interrupted during the wait for read.");
}
}
try {
while (read.ready()) {
readFromFile = read.readLine();
}
} catch (IOException ex) {
System.out.println("Error in reading from FIFO.");
}
readable = false;
notify();
return readFromFile;
}
synchronized void waitForFifo() {
while (readable) {
try {
wait();
} catch (InterruptedException ex) {
Logger.getLogger(Detect.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
while (!read.ready()) {
Thread.sleep(1000);
System.out.println("Sleeping due to lack of activity in FIFO in thread : " + Thread.currentThread().getName());
}
} catch (IOException | InterruptedException ex) {
Logger.getLogger(Detect.class.getName()).log(Level.SEVERE, null, ex);
}
readable = true;
notify();
}}
Next, the thread which will read from it.
public class ReadThread extends Thread {
Detect detect;
private boolean shouldBeRunning;
public ReadThread(Detect detect) {
this.detect = detect;
shouldBeRunning = true;
}
#Override
public void run() {
while (shouldBeRunning) {
String added = detect.readFromFifo();
System.out.println(added);
}
}
public void stopRunning() {
shouldBeRunning = false;
}}
Finally, the thread which will check if the FIFO is empty or not.
public class NotifyThread extends Thread {
Detect detect;
private boolean shouldBeRunning;
public NotifyThread(Detect detect) {
this.detect = detect;
shouldBeRunning = true;
}
#Override
public void run() {
while (shouldBeRunning) {
detect.waitForFifo();
}
}
public void stopRunning() {
shouldBeRunning = false;
}}
In main I just create the threads and start them.
Detect detect = new Detect();
NotifyThread nThread = new NotifyThread(detect);
ReadThread rThread = new ReadThread(detect);
nThread.start();
System.out.println("Started the notifier thread in : " + Thread.currentThread().getName());
rThread.start();
System.out.println("Started the reading thread in : " + Thread.currentThread().getName());
Is there any alternative to calling sleep or another approach I can take to replace the sleep with something else? I have already read other questions related to this topic and I am still uncertain/have not understood whether this sort of case is indicated for sleep or not.
UPDATE: As #james large said, there was no need to poll for ready. I was not aware that if there is no line, the readLine() will 'sleep' and there was no need to poll it after all. I removed the notifier thread, and I simply kept the ReadThread which will call the Detect readFromFifo() method and it all works good. #dumptruckman, thanks for the suggestion. Although it doesn't apply to my case, I didn't know of the WatchService and it was a good read, good stuff to know. #Nyamiou The Galeanthrope, the timer would have been useful, but as I already said, I only keep one thread to execute the same method and it works as intended.#Krzysztof Cichocki, thanks for pointing out there are issues. I was aware of that, otherwise I wouldn't have asked this question.
I am a bit stumped on a new concept I am learning in my concepts of programming languages class. Any info would be great. Reader Writer Problem as follows:
This classical problem requires process synchronization for reading and writing. Therefore, you need a synchronization controller before you define and create threads for reading and writing. The following is a controller class (with two methods left out for you to implement). To keep the programming simple, when you write thread classes for reading and writing (say, three readers and one writer), you only need to symbolically print a message when starting reading or writing, and print another message when finishing reading or writing (thus there is no need to create actual shared content each thread reads or writes about).
Here is what I have. I think I am missing something fundamental with threads. Please note that the controller class and methods is given and required, except the startWriting() and stopWriting() must be implemented by me. Thank you.
class Controller {
private int activeReaders = 0;
private boolean writerPresent = false;
protected boolean writeCondition() {
return activeReaders == 0 && !writerPresent;
}
protected boolean readCondition() {
return !writerPresent;
}
protected synchronized void startRead() {
while (!readCondition())
try { wait(); } catch (InterruptedException ex) {}
++activeReaders;
}
protected synchronized void stopRead() {
--activeReaders;
notifyAll();
}
protected synchronized void startWriting(){
writerPresent = true;
System.out.println("Writing has begun");
}
protected synchronized void stopWriting(){
System.out.println("Reading is now available");
writerPresent = false;
}
public static void main(String [] args){
Controller c = new Controller();
Thread tRead1 = new Thread(new Runnable() {
#Override
public void run(){
c.startRead();
System.out.println("Reader 1 has started reading");
c.stopRead();
System.out.println("Reader 1 has stopped reading");
}
});
Thread tRead2 = new Thread(new Runnable() {
#Override
public void run(){
c.startRead();
System.out.println("Reader 2 has started reading");
c.stopRead();
System.out.println("Reader 2 has stopped reading");
}
});
Thread tRead3 = new Thread(new Runnable() {
#Override
public void run(){
c.startRead();
System.out.println("Reader 3 has started reading");
c.stopRead();
System.out.println("Reader 3 has stopped reading");
}
});
Thread tWrite1 = new Thread(new Runnable() {
#Override
public void run(){
c.startWriting();
c.stopWriting();
}
});
tRead1.start();
tRead2.start();
tWrite1.start();
try {
tWrite1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tRead3.start();
}
}
First, I recommend you go to the javadocs and read the method definitions for wait, notify, and notifyall. This is the basic waiting / locking / notifying system in Java.
In terms of Readers and Writers, the readers should all be reading from the writer, and put into suspension using wait on the writer if there is no content available. If you have multiple writers, you can do the same thing with the readers waiting on a messagequeue. When the writer writes and has more data to be consumed by a reader, it should call notify on itself (the writer) to wake one consumer up to grab the new data.
And to give you an idea of when you could/should use notifyAll:
Thread.join works by invoking wait on the Thread being joined with. Upon thread death, Thread calls notifyAll to wake up all threads that are waiting for it to finish.
Hi guys, I'm new to Java and I'm takin a course at Uni. I have gotten a task to write a small game that generates a random nr that the player will guess. After guessing the player is supposed to get the option to play again or WAIT and automatically come back to the main menu.
First I tried thread.sleep(5000) but it got stuck because it was waiting for user input (nextLine). Then a friend told be about timer and timertask, which i used and now my game is almost working.
The only problem is when i call a new method from my run() method the old (play again Y/N) thread running in the background is not ended. So when my menu appears after 5 seconds, my first input is connected to the play again Y/N choice and not the main menu options. Here are the kod parts:
public void tryAgain() {
Timer timer = new Timer();
Task timerTask = new Task();
int y = 1;
String yesNo = sc.nextLine();
System.out.println("Try again Y/N");
Statistics.setGames(games);
timer.schedule(timerTask, 5000);
do {
try {
yesNo = sc.nextLine();
if (yesNo.equals("Y") || yesNo.equals("y")) {
guesses = 0;
y = 2;
timerTask.cancel();
playGame();
} else if (yesNo.equals("N") || yesNo.equals("n")) {
y = 3;
timerTask.cancel();
Statistics.setGames(games);
menu.showMainMenu();
} else {
System.out.println("Wrong input, try Y or N:");
}
} catch (Exception e) {
sc.next();
System.out.println("Wrong input, try Y or N:");
}
} while (y == 1);
}
and :
import java.util.TimerTask;
class Task extends TimerTask {
play menu = new play();
public void run() {
Statistics.getGames();
menu.menu.showMainMenu();
cancel();
}
}
You cannot interrupt blocking reads. But you can use the BufferedReader.ready() method, which will tell us whether the underlying stream is ready to be read.
Let's implement a non blocking reader:
public class OurNonBlockingConsoleReader implements Callable<String> {
public String call() throws IOException {
BufferedReader sysInReader = new BufferedReader(new InputStreamReader(System.in));
String answer;
do {
System.out.println("Try again Y/N");
try {
while (!sysInReader.ready()) {
Thread.sleep(100);
}
answer = sysInReader.readLine();
} catch (InterruptedException e) {
return null;
}
} while (!"y".equalsIgnoreCase(answer) && !"n".equalsIgnoreCase(answer));
return answer;
}
}
Next, we call this reader with a timeout, using the ExecutorService and the Future from java.util.concurrent package:
public void tryAgain() throws InterruptedException, ExecutionException {
ExecutorService readerExecutor = Executors.newSingleThreadExecutor();
Future<String> readerResult = readerExecutor.submit(new OurNonBlockingConsoleReader());
try {
String answer = readerResult.get(5, TimeUnit.SECONDS);
if ("y".equalsIgnoreCase(answer)) {
playTheGame();
} else {
goToMainTheMenu();
}
} catch (TimeoutException e) {
goToMainTheMenu();
} finally {
readerExecutor.shutdownNow();
}
}
The readerResult.get(...) call will wait 5 seconds for a valid answer. It there is no valid answer returned from OurNonBlockingConsoleReader.call, the Future.get will raise a TimeoutException.
Addressing only your immediate problem:
Your run method needs to set y to something other than 1 (perhaps 0), then call interrupt on Y/N thread. This will kick it out of a blocking read with an InterruptException or ClosedByInterruptException. (Your catch block will need to be smarter.) Then the Y/N loop will finish because y is not 1. End of problem.
For this to work, y needs to be declared volatile, or each thread might use its own copy. (Accessing it only within synchronized blocks will work also.)
Added Example:
public class YesNo {
private volatile Thread tryAgainThread;
private volatile int y = 1;
public doNotTryAgain() {
y = 0;
tryAgainThread.interrupt();
}
// Called only from tryAgainThread thread.
public void tryAgain() {
do {
try {
// Exactly what you have now.
...
}
catch (Exception e) {}
} while (y == 1);
}
....
class Task extends TimerTask {
public YesNo ynInstance;
...
public void run() {
ynInstance.doNotTryAgain();
Statistics.getGames();
...
}
}
I'll let you figure out how to set tryAgainThread, which is the thread the tryAgain method is called--and is looping--on. Also, Task needs to know the relevant (and probably only) instance of the class that contains the tryAgain call running in the 'tryAgainThread'. In your case some static public fields will do the job, but ideally you'd want something more elegant.
Also, catch (Exception e) {} will work fine, but ideally you'd check your exceptions better.
I'm working on making an interface for a robot. My Robot class has methods that include movement, stopping movement and reading sensor data. If at all possible, I'd like to have certain methods run under a given thread and certain other methods run under another. I'd like to be able to send the command to move to the robot object, have the thread executing it sleep duration milliseconds and then stop movement, but I'd like the stop() method able to be called and interrupt the thread executing the movement. Any help is greatly appreciated.
public class robotTest
{
public static void main(String[] args) throws InterruptedException
{
Robot robot = new Robot(); //Instantiate new Robot object
robot.forward(255, 100, Robot.DIRECTION_RIGHT, 10); //Last argument representing duration
Thread.sleep(5000); //Wait 5 seconds
robot.stop(); //Stop movement prematurely
}
}
I would suggest instantiating your Robot class with an ExecutorService that you can use for moving asynchronusly. Submit the movement request to your service and use the Future returned to 'stop' the move request.
class Robot{
final ExecutorService movingService = Executors.newSingleThreadExecutor();
private volatile Future<?> request; //you can use a Deque or a List for multiple requests
public void forward(int... args){
request = movingService.submit(new Runnable(){
public void run(){
Robot.this.move(args);
}
});
}
public void stop(){
request.cancel(true);
}
}
If I'm understanding you correctly then yes, you can call methods on an object from any given thread. However, for this to work in a bug free fashion the robot class needs to be thread safe.
Make sure all your calls to Robot come from a thread (a class extending Thread that you create) with permissions to make the calls. Add this method to your call.
Note: this code is far from perfect. But it may give you some ideas you can use in your application.
public void stop() throws NoPermissionException {
checkStopPermission(); // throws NoPermissionException
// rest of stop here as normal
}
/**
* Alternatively you could return a boolean for has permission and then throw the NoPermissionException up there.
*/
private void checkStopPermission() throws NoPermissionException() {
try {
Thread t = Thread.currentThread();
RobotRunnableThread rrt = (RobotRunnableThread)t; // may throw cast exception
if(!rrt.hasPermission(RobotRunnableThread.STOP_PERMISSION)) { // assume Permission enum in RobotRunnableThread
throw new NoPermissionExeception();
}
} catch(Exception e) { // perhaps catch the individual exception(s)?
throw new NoPermissionException();
}
}
You have to start a new background thread when you instantiate a Robot that would handle movement. The thread would sit there, waiting for a signal from forward or stop and do the appropriate thing.
You will have to synchronize the threads using either semaphores, wait handles, or other inter thread communication elements.
The least robust solution that wastes the most CPU (this is pseudo code since I have not used Java in a while, might be intermixed with .NET APIs):
public class Robot implements IRunnable {
public Robot() {
new Thread(this).Start();
}
private int direction = 0;
private int duration = 0;
private bool go = false;
public void Run() {
DateTime moveStartedAt;
bool moving = false;
while(true) {
if(go) {
if(moving) {
// we are already moving
if((DateTime.Now - moveStartedAt).Seconds >= duration) {
moving = false;
}
} else {
moveStartedAt = DateTime.Now;
moving = true;
}
} else {
moving = false;
}
}
}
public void forward(int direction, int duration) {
this.direction = direction;
this.duration = duration;
this.go = true;
}
public void stop() {
this.go = false;
}
}
(the above code should be modified to be Java for better answer)
What is wrong with this code:
The Run() method consumes one whole Core (it has no sleeps)
Calling stop() and then forward() right away can result in a race condition (the Run() has not seen the stop yet, but you already gave it another forward)
There is no way for Run() to exit
You can call forward() to redirect the move that is already in progress
Others?