This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
i've been making a countdown program, and i came up with this.
package main;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class Gatoo extends JFrame implements ActionListener {
private int sec, min, secTot, since = 999;
private long lastTime;
private JTextField mm = new JTextField(2), ss = new JTextField(2);
private JLabel minLab = new JLabel("Minutes:"), secLab = new JLabel(
"Seconds:");
private JButton start = new JButton("Start");
private Clip done;
private boolean started = false;
private static final long serialVersionUID = 4277921337939922028L;
public static void main(String[] args) {
Gatoo cake = new Gatoo("Title");
cake.pack();
cake.setSize(800, 600);
cake.setLocationRelativeTo(null);
cake.setDefaultCloseOperation(3);
cake.setVisible(true);
cake.run();
}
public Gatoo(String s) {
super(s);
setLayout(new FlowLayout());
start.addActionListener(this);
add(minLab);
add(mm);
add(secLab);
add(ss);
add(start);
}
#Override
public void actionPerformed(ActionEvent e) {
started = true;
}
public void play(File file) throws MalformedURLException,
UnsupportedAudioFileException, IOException,
LineUnavailableException {
AudioInputStream ais = AudioSystem.getAudioInputStream(new File(
"lib/done.wav"));
DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
done = (Clip) AudioSystem.getLine(info);
done.open(ais);
done.start();
}
public void run() {
while (true) {
System.out.print("");// needed?
if (started) {
try {
min = Integer.parseInt(mm.getText());
sec = Integer.parseInt(ss.getText());
secTot = (min * 60) + sec;
lastTime = System.currentTimeMillis();
while (secTot > 0) {
since = (int) (System.currentTimeMillis() - lastTime);
if (since > 998) {
lastTime = System.currentTimeMillis();
secTot--;
}
}
play(new File("done.wav"));
} catch (NumberFormatException exception) {
System.out.println("Minutes and seconds must be numbers.");
return;
} catch (Exception exception) {
exception.printStackTrace();
}
started = false;
}
}
}
}
In the while loop at the end the countdown code doesn't execute without a print / println statement inside. How come? The program works perfectly fine with the print statement though.
First and foremost, your program is thread-unsafe because boolean started is a shared variable, but it is neither volatile nor accessed within synchronized blocks.
Now, accidentally, PrintStream#print is a synchronized method and, on any actual architecture, entering and exiting a synchronized block is implemented using memory barrier CPU instructions, which cause a complete synchronization between the thread-local state and main memory.
Therefore, by pure accident, adding the print call allows the setting of started flag by one thread (the EDT) to be visible by another (the main thread).
You have poor design for Swing application.
Don't use while(true) loop in your run() method. Read more about Concurency in Swing.
Call events with help of Listeners(ActionListener e.g.) instead of flags(started here).
Instead of counting time use Swing Timer.
Change your run() method like next:
public void run() {
min = Integer.parseInt(mm.getText());
sec = Integer.parseInt(ss.getText());
secTot = (min * 60) + sec;
Timer timer = new Timer(1000*secTot, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
play(new File("done.wav"));
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
timer.start();
}
actionPerformed() method :
#Override
public void actionPerformed(ActionEvent e) {
run();
}
and remove cake.run() in main method.
Look, I made a SSCCE reproducing this behavior. It is a really good question.
public class ThreadRacing implements Runnable
{
public boolean started = false;
public static void main(String[] args)
{
new ThreadRacing().test();
}
public void test()
{
new Thread(this).start();
try
{
Thread.sleep(1000);
} catch (Exception e)
{
}
started = true;
System.out.println("I did my job");
}
#Override
public void run()
{
while (true)
{
//System.out.print("");
if (started)
{
System.out.println("I started!!");
}
}
}
}
This prints: "I did my job". Nothing more. Adding a volatile keyword actually fixes the problem.
To me, it looks like the second Thread gets not notified about the update to started because he is too bussy.
I would surmise that your busy-wait loop is hogging the CPU so severely it is unable to do anything. The print statement is causing just enough of a thread context switch that it is able to get other work done.
Edit: Okay, I did a little testing. I was able to reproduce OP's problem on the HotSpot Server VM. Using Thread.currentThread().setPriority(Thread.MIN_PRIORITY); did not fix it, so it is not a starvation issue. Setting the variable to volatile as #MartinCourteau, #MarkoTopolnik suggested, did fix it. That makes sense. I couldn't originally reproduce the problem on the HotSpot Client VM; apparently its optimizations are too weak for it to cache the started variable.
(Still, if the Java audio thread had a lower than normal thread priority and it were a single-CPU system, starvation was a plausible hypothesis.)
Related
So I'm receiving numerous messages from a stream - well, it's not a stream per se, it's really a method that's fired off when a message is received - and I would like to count the number of messages received in 10 seconds.
Here's what I have so far:
package com.example.demo;
import java.net.URI;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
public class ExampleClient extends WebSocketClient {
private float messagesRecievedCount;
public ExampleClient(URI serverUri) {
super(serverUri);
System.out.println("Created object");
setMessagesRecievedCount(0);
}
#Override
public void onOpen(ServerHandshake serverHandshake) {
System.out.println("Connection established!");
}
#Override
public void onMessage(String s) {
setMessagesRecievedCount(getMessagesRecievedCount() + 1);
}
public void getMessagesPerMinute(){
float start = getMessagesRecievedCount();
float end = 0;
long ten = System.currentTimeMillis() + 1000;
while(System.currentTimeMillis() < ten) {
end = getMessagesRecievedCount();
}
System.out.println("start: "+start+" end: "+end+
"Total messages: "+ (end-start)+"\n");
}
public float getMessagesRecievedCount() {
return messagesRecievedCount;
}
public void setMessagesRecievedCount(float messagesRecievedCount) {
this.messagesRecievedCount = messagesRecievedCount;
}
}
I have a global variable messagesRecievedCount which keeps a running count of messages received from a websocket stream. Whenever a message is received the onMessage() method is fired and it updates the message count. I want to count the number of messages received in 10 seconds (and extrapolate it to a minute) - for which I have the getMessagesPerMinute().
Obviously the way I'm doing it is not smart - it's blocking and the count of messages after 10 seconds is the same (when actually it isn't, I've actually received 20 messages). I feel like I should be doing threads but I don't know how to go about it. What would you suggest? I'm really new to this and just tinkering around.
This is the main class where I'm calling ExampleClient.java from:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.WebSocketSession;
import java.net.URI;
import java.net.URISyntaxException;
#SpringBootApplication
public class DemoApplication {
private WebSocketSession clientSession;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
public DemoApplication () throws URISyntaxException {
ExampleClient c = new ExampleClient( new URI( "wss://example.com/" ) );
c.connect();
c.getMessagesPerMinute();
}
}
The c.connect() establishes the connection and the onMessage() is triggered soon after!
Your code actully runs fo 1 second (1000ms, I don't know if this is a typo or a voluntary simplification). One other problem is that it calls end = getMessagesRecievedCount(); repeatedly inside a while loop, while you actually need only the starting and final value. A way to solve this would be using Thread.sleep() (if you never need to cancel the counting midway):
public void getMessagesPerMinute(){
float start = getMessagesRecievedCount();
float end = 0;
try{
Thread.sleep(10000);
}
catch(InterruptedException e){
System.out.println("do something");
}
end = getMessagesRecievedCount();
System.out.println("start: "+start+" end: "+end+
"Total messages: "+ (end-start)+"\n");
}
For blocking the important thing is that this code runs in a different thread that the one updating the value of messagesRecievedCount or doing other things that you may want to do in the meanwhile, so calling it inside a new thread is probably the best solution. I'm not familiar with the framework you are using so it may be already using different threads that better suit this purpose.
If you intend to do something more with the variable messagesRecievedCount some synchronization would be required, but for an estimate of the number of messages for minute this should be good enough.
Here is some test code I used that you can hopefully adapt to better suit your case and play with to pinpoint the problem. The difference is quite constant in this case, but the values are clearly updated. Making the ExampleClient instance public is a shortcut which should probaby be avoided in the actual code.
public class Test{
public static ExampleClient example=new ExampleClient();
public static void main(String[] args){
Thread a=new MessagesPerTenSecondFetcher();
Thread b=new MessagesPerTenSecondFetcher();
Thread c=new MessagesPerTenSecondFetcher();
Thread d= new MessageProducer();
a.start();
d.start();
b.start();
try{
Thread.sleep(2000);
}
catch(InterruptedException e){
System.out.println("do something");
}
c.start();
}
}
class ExampleClient {
private float messagesRecievedCount;
public void onMessage(String s) {
setMessagesRecievedCount(getMessagesRecievedCount() + 1);
}
public void getMessagesPerMinute(){
float start = getMessagesRecievedCount();
float end = 0;
try{
Thread.sleep(10000);
}
catch(InterruptedException e){
System.out.println("do something");
}
end = getMessagesRecievedCount();
System.out.println("start: "+start+" end: "+end+
"Total messages: "+ (end-start)+"\n");
}
public float getMessagesRecievedCount() {
return messagesRecievedCount;
}
public void setMessagesRecievedCount(float messagesRecievedCount) {
this.messagesRecievedCount = messagesRecievedCount;
}
}
class MessagesPerTenSecondFetcher extends Thread{
#Override
public void run(){
Test.example.getMessagesPerMinute();
}
}
class MessageProducer extends Thread{
#Override
public void run(){
for(int i =0; i<100;i++){
Test.example.onMessage("a");
try{
Thread.sleep(130);
}
catch(InterruptedException e){
System.out.println("do something");
}
}
}
}
I've got a program, in java, that is just a simple autoclicker. What I'm looking to do is make it so that with the press of a key (say, F9) the infinite loop in the program runs without interruption - and when another key (say, F10) is pressed, the program pauses, such that once I press F9 again the program resumes. Here's the code that I've got:
package SimpleCode;
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.MouseEvent;
public class AutoClicker {
public static void MainFunction(){
while(true){
leftClick();
delay(6.5);
}
}
protected static void delay(double seconds){
createMacro();
macro.delay((int(seconds * 1000.0));
}
protected static void leftClick(){
createMacro();
macro.mousePress(MouseEvent.BUTTON1_MASK);
macro.mouseRelease(MouseEvent.BUTTON1_MASK);
}
private static Robot macro = null;
private static void createMacro(){
try {
macro = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
}
public static void main(String args[]){
MainFunction();
}
}
I suppose to interrupt the loop, I must find a way to make the "while(true)" part false once F10 is pressed, but that's all that I can reason. I'm not sure how pressing F9 would start the program.
Note: credits to SimpleCode's youtube video on the subject for the above framework.
You're going to want to do something like
private boolean running;
private void onPressf9Action(){
running = true;
}
while(running) {
//perform action
}
private void someOtherAction(){
running = false;
}
I've been trying to learn java for a few weeks now, and I'm working on a pretty simple autoclicker.
The clicker itself works, but my problem is that my GUI never shows up.
The GUI runs just fine when I run the GUI file itself, but when I'm trying to run it from my main program (different file) it never shows. The clicker works fine all the time though. I'm sure the problem is something really simple that I have simply missed, but this is now my 4th day without any clue on what might be wrong with it, so decided I'd ask here.
Beware - the code is really messy atm, because I've been trying pretty much everything possible to get it working.
This is the code in the main program trying to run the GUI.
package autoclicker;
import java.awt.AWTException;
/**
* The main program for the autoclicker.
*/
public class AutoClicker {
public static void main(String[] args) throws AWTException {
Click click = new Click(true);
click.clicker();
try {
Swingerinos sw = new Swingerinos();
sw.initialize();
}
catch (AWTException e) { e. printStackTrace(); System.exit(-1); }
}
}
And this is the whole GUI file.
package autoclicker;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class Swingerinos extends Click implements WindowListener,ActionListener {
private int numClicks = 0;
TextField text;
private JFrame frame;
/**
* #wbp.nonvisual location=181,19
*/
private final JLabel lblAutoclicker = new JLabel("AutoClicker");
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Swingerinos window = new Swingerinos();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Swingerinos() throws AWTException {
initialize();
}
/**
* Initialize the contents of the frame.
*/
public void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 109);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.WEST);
JButton btnNewButton = new JButton("Toggle On / Off");
text = new TextField(20);
text.setLocation(100, 100);
btnNewButton.addActionListener( this);
btnNewButton.setToolTipText("Toggles the autoclicker on / off.");
panel.add(btnNewButton);
panel.add(text);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
toggle();
numClicks++;
text.setText(""+numClicks);
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowOpened(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
}
I know the GUI file is really messy (there's 2x initialize(), one in the main program and one in the GUI file, and lots of other stuff, but I'm just too confused as for what to do now.
EDIT: I added the whole main program code, also this is the code for the autoclicker.
package autoclicker;
import java.awt.*;
import java.awt.event.InputEvent;
public class Click {
private boolean active;
private Robot robot;
public Click(boolean active, Robot robot) {
this.active = active;
this.robot = robot;
}
public Click() throws AWTException {
this(false, new Robot());
}
public Click(boolean active) throws AWTException {
this(active, new Robot());
}
//TODO: add click.toggle() to somewhere and control da clicker
public void toggle() {
active = !active;
}
public void clicker() {
while (active) {
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.setAutoDelay(10000);
}
}
}
Expanding JB Nizet's comment(s) into an answer.
The immediate cause:
When the JVM calls your code, it is run on the main thread. It calls main(String[]), as you know. You posted two main methods, only one of which is relevant to your nothing-is-happening problem: AutoClick#main(String[]). Let's go through it:
Click click = new Click(true);
click.clicker();
This first of the above two lines obviously calls the constructor of Click, which sets the active variable to true. So far so good. The second line is much more interesting. It calls Click#clicker(). Let's look at that method:
public void clicker() {
while (active) {
// <snip>
}
}
This method is the problem. Since you haven't started any other threads, the main thread is the only one you have at that moment, the only thread on which you can execute code. When this loop is executed it only finishes when the active variable is set to false. As long as it is true, it will keep looping. This means that Click#clicker() only returns if active is set to false. But, you never do that in the loop itself, meaning you need a thread different from the thread executing the loop to change active. So, how many threads do we have? 1, the main thread. See the problem? Because the loop never ends, the main thread never reaches the statements in the main method after click.clicker().
Simple solution
You could just set a fixed number of iterations:
public void clicker() {
int i = 0;
while (i < 100) { // iterate 100 times
// <snip>
++i;
}
}
Or using a for-loop (recommended):
public void clicker() {
for (int i = 0; i < 100; ++i) {
// <snip>
}
}
This eliminates the need for the active variable and hence the need for another thread.
A somewhat more complicated solution
If you really want the active variable, you'll need to have multiple threads. This is conveniently known as "multithreading"1, a very complicated topic. Luckily, we only need a bit of it, so it is only a bit complicated.
Don't just call the method Click#clicker() like you would normally. This creates your current problem. You'll need a worker thread, which can call the method. The easiest way to create a new thread is to call the constructor of the class Thread which takes a single argument of type Runnable. Like this:
Thread worker = new Thread(new Runnable() {
public void run() {
click.clicker();
}
});
This returns relatively quickly and leaves the Click#clicker() method running on another thread. Your main thread is now free to execute the other statements and even call click.toggle() after a while.
As JB Nizet pointed out, there are some other problems with your code. For example, Swingerinos shouldn't extend Click, but have an instance variable of type Click (http://en.wikipedia.org/wiki/Composition_over_inheritance) (as JB Nizet pointed out). Also, you shouldn't need to implement WindowListener to just call System.exit() when the window closes if you already call frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. To get all kinds of feedback (not limited to but including this kind of issues, style and design) on working code2 I highly recommend the StackExchange website codereview.stackexchange.com
1: I by no means consider myself even remotely an expert on threading, so I won't go into it. If you want to know more about it, google it - there's lots of texts on multithreading - or ask another question - if you have a specific problem.
2: this is important: broken code is off-topic on Code Review.
I have a pretty complex problem. In my current project, I have a GUI written in Java and a computing engine written in C++.
These are displays in Java which access to data in C++, and I have some issues with concurrency.
There are a long story in this code, so I can't just rewrite all (even if I want it occasionnaly :p).
When the engine modify the datas, it acquire a mutex. It's pretty clean from this side.
The problem is GUI. It is Java Swing, and it access the data without any control, from EventDispatchThread, or from any thread, and acquire the c++ mutex (via JNI) for each unitary access to the kernel (which is not good, for performance and data consistancy).
I already refactor it to encapsulate the lock code in Java in a "NativeMutex" which call the native functions lock and unlock from JNI.
I want write a "ReentrantNativeLock", to avoid rewrite all and just add some high-level lock.
But this ReentrantNativeLock must deal with the EventDisplayThread.
I have defined that this lock implementation must avoid that the EDT takes the mutex (by throwing an exception when the lock method is called from EDT), but just return when the lock is already owned by another thread (to deal with SwingUtilities.InvokeAndWait without rewrite all the dirty code of this application)
Conceptually, It's ok because I focus on synchronization between the C++ engine and the JAVA GUI, but it's not safe from the Java-side.
So I want to go further. If I can know which threads are waiting for EDT (which are the threads that have called "InvokeAndWait"), I can implement something safer.
I will be able to check if the owner thread is waiting for EDT, and avoid some ununderstandable but probable bugs which will annoy my futur-myself and my coworker.
So, how can I know which threads are waiting for EDT (which are the threads that have called "InvokeAndWait")
(If I described the context, it's because I am open to listen other ideas which could solve my problem... Only if they doesn't imply a lot of rewrite.)
As some comments make me believe that the context isn't well described, I post some code which, I hope, will explicit my problem.
It's a basic Decorator, m_NativeLock is the non-reentrant nativeLock.
public class ReentrantNativeLock implements NativeLock {
/**
* Logger
*/
private static final Logger LOGGER = Logger.getLogger(ReentrantNativeLock.class);
public ReentrantNativeLock(NativeLock adaptee) {
m_NativeLock = adaptee;
}
public void lock() {
if (!SwingUtilities.isEventDispatchThread()) {
m_ReentrantLock.lock();
if (m_ReentrantLock.getHoldCount() == 1) { // Only the first lock from a thread lock the engine, to avoid deadlock with the same thread
m_NativeLock.lock();
}
}
else if (m_ReentrantLock.isLocked()) {
// It's EDT, but some thread has lock the mutex, so it's ok... We assume that the locked thread as called SwingUtilities.invokeAndWait... But if I can check it, it will be better.
LOGGER.debug("Lock depuis EDT (neutre). Le lock a été verrouillé, l'accès moteur est (à priori) safe", new Exception());
}
else {
// We try to avoid this case, so we throw an exception which will be tracked and avoided before release, if possible
throw new UnsupportedOperationException("L'EDT ne doit pas locker elle-même le moteur.");
}
}
public boolean tryLock() {
if (!SwingUtilities.isEventDispatchThread()) {
boolean result = m_ReentrantLock.tryLock();
if (result && m_ReentrantLock.getHoldCount() == 1) {
result = m_NativeLock.tryLock();// Only the first lock from a thread lock the engine, to avoid deadlock with the same thread
if (!result) {
m_ReentrantLock.unlock(); // If the trylock on engin fail, we free the lock (I will put it in a try{}finally{} if I valid this solution.
}
}
return result;
}
else if (m_ReentrantLock.isLocked()) {
// It's EDT, but some thread has lock the mutex, so it's ok... We assume that the locked thread as called SwingUtilities.invokeAndWait... But if I can check it, it will be better.
LOGGER.debug("Lock depuis EDT (neutre). Le lock a été verrouillé, l'accès moteur est (à priori) safe", new Exception());
return true;
}
else {
// We try to avoid this case, so we throw an exception which will be tracked and avoided before release, if possible
throw new UnsupportedOperationException("L'EDT ne doit pas locker elle-même le moteur.");
}
}
public void unlock() {
if (!SwingUtilities.isEventDispatchThread()) {
if (m_ReentrantLock.getHoldCount() == 1) {
m_NativeLock.unlock();
}
m_ReentrantLock.unlock();
}
else {
LOGGER.debug("Unlock depuis EDT (neutre). Le lock a été verrouillé, l'accès moteur est (à priori) safe", new Exception());
}
}
final ReentrantLock m_ReentrantLock = new ReentrantLock();
final NativeLock m_NativeLock;
}
What you can do is have your own EventQueue that records events to dispatch, from which Thread they are created and if the Thread is waiting for the event to be dispatched (so, in case a Thread invokes invokeAndWait).
First, push your own queue:
ThreadTrackingEventQueue queue = new ThreadTrackingEventQueue();
Toolkit.getDefaultToolkit().getSystemEventQueue().push(queue);
In your implementation of the queue:
override postEvent, check if it's an InvocationEvent and if it's waiting to be notified. In such case track the Thread and the corresponding event
override dispatchEvent to unmark the calling thread as waiting for the EDT.
Complete example (watch out, it sleeps on the EDT to make collisions happen, but it should never be done in an application):
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InvocationEvent;
import java.lang.reflect.Field;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestEventQueue {
private final ThreadTrackingEventQueue queue;
public static class ThreadTrackingEventQueue extends EventQueue {
private Field notifierField;
private Hashtable<AWTEvent, Thread> waitingThreads = new Hashtable<AWTEvent, Thread>();
public ThreadTrackingEventQueue() throws NoSuchFieldException, SecurityException {
notifierField = InvocationEvent.class.getDeclaredField("notifier");
notifierField.setAccessible(true);
}
#Override
public void postEvent(AWTEvent event) {
if (!SwingUtilities.isEventDispatchThread() && event.getClass() == InvocationEvent.class) {
try {
Object object = notifierField.get(event);
if (object != null) {
// This thread is waiting to be notified: record it
waitingThreads.put(event, Thread.currentThread());
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
super.postEvent(event);
}
#Override
protected void dispatchEvent(AWTEvent event) {
try {
super.dispatchEvent(event);
} finally {
if (event.getClass() == InvocationEvent.class) {
waitingThreads.remove(event);
}
}
}
public Hashtable<AWTEvent, Thread> getWaitingThreads() {
return waitingThreads;
}
}
public TestEventQueue(ThreadTrackingEventQueue queue) {
this.queue = queue;
}
private void initUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextArea textArea = new JTextArea(30, 80);
JButton button = new JButton("Start");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
start();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
frame.add(new JScrollPane(textArea));
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
Timer t = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Hashtable<AWTEvent, Thread> waitingThreads = (Hashtable<AWTEvent, Thread>) queue.getWaitingThreads().clone();
if (waitingThreads.size() > 0) {
for (Thread t : queue.getWaitingThreads().values()) {
textArea.append("Thread " + t.getName() + " is waiting for EDT\n");
}
} else {
textArea.append("No threads are waiting\n");
}
}
});
t.start();
}
protected void start() throws InterruptedException {
final Random random = new Random();
ExecutorService pool = Executors.newFixedThreadPool(50);
for (int i = 0; i < 50; i++) {
pool.submit(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
System.out.println("sleeping before invoke and wait");
Thread.sleep(random.nextInt(2000) + 200);
System.out.println("invoke and wait");
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
try {
System.out.println("sleeping on EDT, bwark :-(");
// Very very bad, but trying to make collisions
// happen
Thread.sleep(random.nextInt(200) + 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
return true;
}
});
}
System.out.println("Invoked all");
}
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
final ThreadTrackingEventQueue queue = new ThreadTrackingEventQueue();
Toolkit.getDefaultToolkit().getSystemEventQueue().push(queue);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
TestEventQueue test = new TestEventQueue(queue);
test.initUI();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
You wrote:
The fact is that some developers have written a lot of code in JAVA
which accesses to data that could be updated from a thread in C++ in
an application that I have to maintain. These codes are called from
different threads, including EDT.
The problem is the EDT that accesses the data. You may need to make some changes to the written code so that the EDT never directly manipulates shared data. This means that the EDT must give data-related tasks to some other threads:
If the EDT need to change some data, it creates a new thread to do the job.
If a thread need to update changes to the GUI, it calls either InvokeLater() or InvokeAndWait().
---------- My Answer (Second Edition) ----------
Hey, there is still some lights at the end of the path.
Let's refactor all the code to make sure there is only one InvokeAndWait() at a time. How to do that? First you need to write a new global method called MyInvokeAndWait(). This method use a lock to ensure that only one thread at a time can call InvokeAndWait(). Then use an IDE to search for all InvokeAndWait() and replace them with MyInvokeAndWait().
Now, inside MyInvokeAndWait(), make sure that when InvokeAndWait() is called, an atomic variable threadId is set to the id of the calling thread (note that the invocation of InvokeAndWait() will block the calling thread). When InvokeAndWait() is finished, the threadId is cleared.
This way, whenever the EDT accesses the data, you can check whether the owner thread has the same id with threadId. If this is the case, let EDT do its job, otherwise throw an exception.
Well... You don't need to ensure only one thread at a time can call InvokeAndWait(). You can add all calling thread id(s) to a collection and then verify that the owner thread id is in the collection.
I have a tiny problem that I can't seem to do right. I have the following class in java:
package pooledtcpconnector.utilities;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class Notifier implements Runnable {
private final ILogger logger;
private Timer mTimer;
private final int Treshold;
private final InputStream ResponseStream;
private final TimerTask DoWaitTask;
public Notifier(final InputStream _ResponseStream, final Integer _Treshold, final ILogger logger) {
this.logger = logger;
mTimer = new Timer();
this.ResponseStream = _ResponseStream;
this.Treshold = _Treshold;
DoWaitTask = new TimerTask() {
#Override
public void run() {
try {
int mSize = ResponseStream.available();
if (mSize >= Treshold) {
mTimer.cancel();
}
} catch (final IOException ex) {
final String ExceptionMessage = ex.getMessage();
logger.LogMessage(
this.getClass().getCanonicalName(),
"Notifier.DoWaitTask:run.ResponseStream.available",
ex.getClass().getCanonicalName(),
new String[]{
ExceptionMessage,
"Parameters:",
String.format("-"),
});
Logger.getLogger(Notifier.class.getCanonicalName()).log(Level.FINE, ex.getMessage(), ex.getCause());
}
}
};
}
#Override
public void run() {
synchronized (this) {
mTimer.scheduleAtFixedRate(DoWaitTask, 250, 200);
// Notification mechanism
notify();
}
}
}
This class would ensure that our application won't start processing the SocketInputStream unless the available method returns at least Treshold. The problem however is that, once I schedule the DoWaitTask with the Timer it runs for eternity. By cancelling the timer the task still runs and the whole application hangs, but more importantly it tries to call available on the stream once it already has been processed and closed. Of course this results in a nice IOException: stream closed.
How could I stop the scheduled task along with the timer? timer.cancel obviously isn't enough.
Regards,
Joey
Use TimerTask.cancel() from within your timer task's run() method. According to the Javadoc for this method:
Note that calling this method from within the run method of a
repeating timer task absolutely guarantees that the timer task will
not run again.
private Timer reportTimer = null;
if (reportTimer != null) {
reportTimer.cancel();
reportTimer = null;
}
reportTimer = new Timer();
reportTimer.schedule(new TimerTask() {}