I'm working on a multithreaded program in Java that uses a shared array to pass data between threads. It's being developed in Netbeans 6.7.1.
One of the threads only seems to work when a breakpoint is placed in it, it doesnt matter where it is.
Running in debug mode with no breakpoints acts the same as running in release - the expected output never arrives.
I can't tell where the problem occurs, as the moment a breakpoint is added and I press continue, it works as expected.
How can I narrow down where/why this problem occurs?
Example code:
result = utils.isBufferFull(AudioDuplex.voiceArray);
if(result == true) {
System.out.println("Taking copy");
voiceArray = AudioDuplex.voiceArray;//.clone();
utils.clearBuffer(AudioDuplex.voiceArray);
}
If a breakpoint is placed on line 2, it is never hit.
A breakpoint on line 3 will be hit, and the expected output will arrive.
It's impossible to tell exactly what's wrong without a lengthier code sample, but in my experience, this kind of behavior is typical of unrecognized producer-consumer problems (see http://en.wikipedia.org/wiki/Producer-consumer_problem).
Basically, what's probably happening is that your producer thread does not have the data available when the consumer thread is requesting it. The basic solution is to keep a semaphore (there is a Sempahore class in java afaik). The producer would post when it has the data, the consumer would wait until the producer posts.
What you're seeing with the break point is you stopping the consumer thread for a long enough period that the producer can offer something. When you don't break, the consumer runs normally, and exits before the producer has anything.
Write the values of the involved variables to a log file, the console or add them to an array and print them as soon as you get the error.
Your problem is probably a runtime issue (a second thread updates an involved variable). Since breakpoints only stop the active thread, the second thread gets its work done so the code works.
Related
I've been tryna find an answer to this for a while but I'm a newbie with little hope left lol
In Java, I have two threads right now:
(main class) Thread A has a while loop listening to commands with Scanner.nextLine()
Thread B prints out "test" every second
When I start both threads, I can't properly type a command without it getting interrupted by Thread B's printing
Output:
test
test
commantest
dctest
ommandtest
test
test
How do I prevent this so I can type commands without any interruptions? I'm open to using ANSI Escape codes and JCurses (or any libraries reallyy) :)
Thanks!
There is no way of preventing this. The two threads are essentially using the same console, which for you looks messed up, but is in fact working exactly as it should. Note that both reading and writing should still work, despite the text on your console being garbled.
If you want to use the console for interacting with the user, you need to ensure that no other threads are using it at the same time. Depending on your use case you could for example send the other prints to a file, named pipe etc. Alternatively, if you are designing the console application with curses, you need to properly design it for multithreading (which, again, boils down to having a single thread dealing with the console, but in a way that keeps things on separate parts of the screen).
Code only executes once.
Disclaimer: Well aware this is an infinite loop, wrote it this way as part of troubleshooting the problem.
update: There was an exception in my error log that got fixed and the problem is still the same, code only executes once
I tried using the same for loop in the same code for a different task (printing a sentence) and it worked fine, problem must be with my JS code.
for(int i=0; i<i+1;i++) {
((JavascriptExecutor)driver).executeScript("window.open()");
ArrayList<String> tabs = new ArrayList<String>(driver.getWindowHandles());
driver.switchTo().window(tabs.get(1));
driver.get("https://www.google.com");
}
Code is executing only once because of an exception being thrown, OR maybe one or more of the network calls you are making is taking too long that makes you believe that the code is executing only once.
To confirm that the value i + 1, which you are using in the for-loop isn't getting replaced by 1, I ran the following loop on my machine:
for (int i = 0; i < i + 1; i++) {
System.out.println(i);
}
...and it goes on to print numbers starting from 0.
I'm just going to clarify this point as an answer, as I expect the question will be removed.
The for loop isn't your problem. You are writing code which has an exception or is blocking the running thread. If you're using another thread to run this, a lack of an UncaughtExceptionHandler can allow it to skip being logged. Similarly the use of Callable<T> can result in exceptions being swallowed from personal experience (perhaps for the same reason?).
If you are blocking the thread running it, then that thread won't run anything else until the blocking method returns control to the context of where you called it.
Given you said you had cases where the loop "ran once" but still printed after, I'm going to go with it being an exception, and the way that you are running your test is flawed. This can be from an uncountable number of reasons, such as a folly System#exit/Runtime#halt call, threads, using a service to run the tests, or running them in some production environment like a game server or a phone (or... A browser?). For future cases, your questions should ideally be reproducible with nothing other than a main method and the code you provide. If you cannot make such an example, at minimum you should provide how you are testing it.
If you do all of that and still have the issue, I think it will either be obvious to you, or the people reading your question here will have a much easier time answering it for you.
So I have some code that I'm modifying. Without going into huge details about what it is actually doing, it can be summarized by creating a file and then sending it to a printer. Essentially the following:
File file = new File("/tmp/12345.pdf");
//Lots of magical code that creates/writes to said file
...
...
...
//sendToPrinter essentially builds up a print command to send to /usr/bin/lp and then executes it.
sendToPrinter(printer, details, file);
file.delete();// This is the line I'm curious about.
My question is that the call to lp is made before we get to file.delete(). However, does this run the risk of creating a race condition where I actually end up deleting the file before the printer is ready?
From preliminary testing, I have yet to see a problem, but something about this bothers me. Have I created the risk of a race condition by doing this?
Edit: Clarification based upon comments. Yes, I'm utilizing lp and sendToPrinter does appear to be waiting for a return code. The code is not asynchronous.
From doc
The join method allows one thread to wait for the completion of
another. If t is a Thread object whose thread is currently executing,
t.join(); causes the current thread to pause execution until t's
thread terminates.
http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join()
I have a multi-thread program which basically has two infinite loop threads plus some GUI (Swing). My two infinite loop threads have their own log4j loggers like this:
static final Category LOG = Category.getInstance(RReceiver.class);
When in GUI I detect exit key I just do System.exit(0):
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getKeyCode()!=27 && e.getKeyCode()!=KeyEvent.VK_BACK_SPACE) return false;
System.exit(0);
return true;
}
The effect in console is like this:
DEBUG 13:07:00,940 [ Receiver] (RReceiver.java:93) - got response len:38
DEBUG 13:07:01,044 [ Receiver] (RReceiver.java:93) - got response len:38
DEBUG 13:07:01,045 [ Receiver] (RReceiver.java:93) - new status dev 4
log4j:WARN No appenders could be found for logger (com.normantech.ibcol.radiobox.RReceiver).
log4j:WARN Please initialize the log4j system properly.
The warning is not appearing always. I suspect there's wrong deinitialisation sequence, but can't figure it out.
Why is that happening? I've tried to use LogManager.shutdown(); but it didn't help. I tried to finish my infinite loops nicely, but it's not best solution, because I I needed to put some additional Thread.sleep(x), tried different x, and actually was not sure if this helped.
The core problem is that you're killing your threads by calling System.exit(), rather than having them shutdown cleanly. This means they may keep running very briefly after everything else is closed but before the JVM actually ends the process, and if they use any shared state during that time (e.g. the logging system), it could be in an inconsistent or broken state as it may have been shutdown. This is not good practice (see http://www.javapractices.com/topic/TopicAction.do?Id=86).
The way to solve this is to properly shutdown your threads before shutting down shared resources (the logging system). Instead of just calling system.exit(), tell each thread that it's time to stop, and wait from them to do so. The cleanest way to do this is to have them check a running boolean on each loop, and to set that boolean to false externally when you want the loop to stop. You can then wait for the thread to notice this boolean and terminate by calling Thread.join() on the given thread instance, or by having the thread set some finished boolean when it's done (best to mark both these booleans as volatile).
If each iteration of your loop takes sometime, or contains wait() or sleep() calls you should look at checking the running boolean more often during the loop, or using Thread.interrupt().
Once this has finished and you're sure every other thread has stopped, you can then call LogManager.shutdown() and actually terminate your process.
I am running Ubuntu 10.10 using Java 6 and can not get FreeTTS to output any audio. I have tried it now on 3 different computers and even asked a buddy of mine to try it on his Ubuntu PC and he had the same problem. There is absolutly no errors that are displayed, after getting the MBROLA i no longer even get the warning about No MBROLA voices detected. blah blah blah..
Using the same computer I ran a virtual box and started Windows XP, i was actually able to get audio when running the HelloWorld.jar and TTSHelloWorld.jar however the freetts.jar is still silent when I try to input my own text.
Command I use.
java -jar lib/freetts.jar -text Hello
When I hit enter it starts up and used to give me the missing MBROLA warning message but now it just sits there until i CTRL-C to stop it.
I dont understand what I am doing wrong and why nobody else is having this problem, when I expierence it on every computer, well it works somewhat on Windows. Can anyone Help me?
Thanks,
John
I'm not sure whether you already managed to solve this one, but I ran into the same problem (Ubuntu 10.10 / JavaSE6). After some investigation of the FreeTTS source I found the culprit, a deadlock, in com.sun.speech.freetts.audio.JavaStreamingAudioPlayer. This deadlock occurs when a Line is opened and the Line is of the type org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine (which is likely to be the default in Ubuntu 10.10 w JavaSE6). Since you'd always want to open a Line to get audio out, this deadlock will always occur.
The cause of this deadlock lies in the fact that in the JavaStreamingAudioPlayer an assumption is made about Line, namely that all LineListeners will be notified of a LineEvent of type open from the same Thread as Line.open() was called, or after the Line has been opened (and the call to Line.open() can return). This is not the case for the PulseAudioSourceDataLine; it first calls all LineListeners from the PulseAudio event Thread, waits for all of them to return and then returns from the open call. With the JavaStreamingAudioPlayer forcing synchronization around the call of Line.open() and the handling of a specific LineListener which task is to see whether the Line ís actually open, the deadlock occurs.
The workaround I chose for solving this problem is to implement an AudioPlayer which doesn't has this problem. I basically copied JavaStreamingAudioPlayer and altered the synchronization blocks on line 196 and line 646 ( full source for reference : http://www.javadocexamples.com/java_source/com/sun/speech/freetts/audio/JavaStreamingAudioPlayer.java.html ).
___: // This is the actual JavaStreamAudioPlayer source, not the fix
195: ...
196: synchronized (openLock) {
197: line.open(format, AUDIO_BUFFER_SIZE); // Blocks due to line 646
198: try {
199: openLock.wait();
200: } catch (InterruptedException ie) {
201: ie.printStackTrace();
202: }
203: ...
643: ...
644: public void update(LineEvent event) {
645: if (event.getType().equals(LineEvent.Type.OPEN)) {
646: synchronized (openLock) { // Blocks due to line 196
647: openLock.notifyAll();
648: }
649: }
650: }
651: ...
I removed both synchronization blocks and instead of ensuring both parts are mutually excluded I used a Semaphore to signal that the Line is in fact open. Of course this is not really a necessity since the PulseAudioSourceDataLine already guarantees being opened upon returning, but it is more likely to play nice when testing the same code on another platform. I didn't dive into the code long enough to say what is going to happen when you open/close/open the line by multiple Threads at the same time. If you're going to do this you are probably looking at a larger rewrite of the JavaStreamingAudioPlayer ;).
Finally, after you have created your new AudioPlayer you'll have to instruct FreeTTS to use your implementation rather than the default JavaStreamingAudioPlayer. This can be done by using
System.setProperty("com.sun.speech.freetts.voice.defaultAudioPlayer", "classpath.to.your.AudioPlayer");
somewhere early in your code.
Hopefully this all works for you.
I am a student who has been trying to make FreeTTS working on its Ubuntu for one week. And finally I found the answer here : thank you so much hakvroot !
Your answer was perfect but you did not put your implementation and this took me quite one hour to understand what was going on in the JavaStreamingAudioPlayer class. To help the other people like me who are not used in "diving" in a completely unknown Java code (I am still a student), I will put here my code and hope it will help other people :) .
First, a more detailed explanation : around line 152, the JavaStreamingAudioPlayer opens a Line. However this operation can require some time so before using it, it wants to check it is opened. In the current implementation, the solution used is to create a LineListener listening to this line and then to sleep (using the wait() method of the threads).
The LineListener will "wake up" the main Thread using a notifyAll() and will do this only when it receives a LineEvent of type "OPEN" which will guarantee that the line has been opened.
However as explained by hakvroot here the problem is that the notification is never sent because of the specific behavior of the DataLine used by Ubuntu.
So I removed the synchronized, wait() and notifyAll() parts of the code but as hakvroot, then your JavaStreamingAudioPlayer might try to use your Line before it is opened : you need to wait for the confirmation with a new mechanism to stop the JavaStreamingAudioPlayer and to wake it up later, when the confirmation arrived.
So I used the Semaphore which havkroot used (see Javadoc for explanations on this lock system) initiated with 1 stack :
when the line is opened it acquires one stack (so 0 remains)
when it wants to use the line it tries to acquire another (so it is stopped)
when the listener gets the event we are looking for, it releases the semaphore
this frees the JavaStreamingAudioPlayer who can go for the next part
do not forget to release again the semaphore so it has again 1 stack for the next line to open
And here is my code :
Declare a Semaphore variable :
private Semaphore hackSemaphore;
Initiate it in the constructor :
hackSemaphore = new Semaphore(1);
Then the first part to replace (see hakvroot to see where to put it) :
line = (SourceDataLine) AudioSystem.getLine(info);
line.addLineListener(new JavaStreamLineListener());
line.open(format, AUDIO_BUFFER_SIZE);
hackSemaphore.acquire();
hackSemaphore.acquire();
opened = true;
hackSemaphore.release();
And the second part :
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.OPEN)) {
hackSemaphore.release();
}
}
I guess had the same issue on Ubuntu 12.04/OpenJDK-6, the execution get stuck in Voice.allocate() with no errors and no response.
I tried using the Oracle/Sun JDK-6 instead of OpenJDK, and it worked fine.
P.S. Nice guide to install SunJDK on Ubuntu and configuring as default
http://www.devsniper.com/ubuntu-12-04-install-sun-jdk-6-7/