I have code which I have been using for years and this morning I noticed property change isn't being called when the task is done. I've got the swing worker set up as an inner class and I put a break point on the String properyName = evt..... and it never hits the break point.
void loadData() {
work2 = new bkgdLoadData();
work2.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if( propertyName.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
if( state == SwingWorker.StateValue.DONE) {
work2 = null;
}
}
}
});
work2.execute();
}
You can see that I set the object work2 to null when the task is finished and now it is no longer being set to null. In the class I added a done routine which it hits when the doinbackground is finished. What is puzzling me is why the property change listener isn't triggered. Something must have changed without my noticing.
protected class bkgdLoadData extends SwingWorker<Integer, Object> {
#Override
protected Integer doInBackground() {
switch(bkgdMode) {
case 0:
doRead();
break;
case 1:
doWrite();
break;
case 2:
runRobot();
break;
}
return 0;
}
#Override
protected void done() {
int i=0;
i++;
}
}
The breakpoint at done is hit but no property change notice is delivered. (I put the done routine for the sole purpose of verifying that the swing worker knows that it is done.)
I looked at the documentation and I don't see that I have to manually fire off some sort of property change, so I am really, really stuck and would appreciate another pair of eyes to tell me what stupid mistake I am mistaking.
Thanks,
Ilan
It turned out my Java was corrupted. Removing JDK 1.6 and reinstalling it from the repository wasn't good enough.
My links in Netbeans to 1.6 got damamged and I had to reinstall Netbeans as well (going over to 7.3.1 in the process). Netbeans would not recognize the repository JDK 1.6 as valid so I had to go to Oracle and get the original version. Netbeans recognized the original and the problem I reported above was no longer a problem.
I removed the void done() routine since it had no purpose other than a place to put a break point. The code as such is OK. Thanks for the help.
Related
first of all I'm not an English native speaker so I apologize for any eventual “weird” writing.
I'm developing a Swing Java application on Eclipse that updates a Jpanel. This panel contains several sub-panels, and I'm constantly switching the panels “modes”, what happens to be a MouseListener changing so they respond in a slightly different manner to the user mouse inputs.
Regardless of what the application do, it's happening an error that seems to have no logical explanation to me. At some point in my code I try to update the panels to what I called neutralMode. This happens on the following method:
//Guarded block (see http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)
private synchronized boolean waitsForUserSatisfactionAnswer()
{
while(!userIndicatedSatisfaction)
{
try {
wait();
} catch (InterruptedException e) {}
}
userIndicatedSatisfaction = false; //reset for future new query
getObjectSetVisualizationPanel().neutralMode();
//getObjectSetVisualizationPanel().queryPatternMode();
return userSatisfied;
}
This updating doesn't work (the call to neutralMode() dont do what is expected). However the call to queryPatternMode() (commented on the line right below) works perfectly. So I decided to COPY queryPatternMode()'s body and PASTE it on neutralMode()'s body ECXATLY THE SAME! AND IT STILL DOESNT WORK!
The methods code is like this:
public void queryPatternMode()
{
System.out.println("Inside queryPatternMode!!!");
System.out.println("panels.size(): " + panels.size());
for (DigitalObjectPanel panel : panels)
{
System.out.println("Inside the loop!!!");
panel.resetBehavior();
panel.setQuerySelectionBehavior(gui);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.validate();
}
});
}
}
public void neutralMode()
{
System.out.println("Inside neutralMode!!!");
System.out.println("panels.size(): " + panels.size());
for (DigitalObjectPanel panel : panels)
{
System.out.println("Inside the loop!!!");
panel.resetBehavior();
panel.setQuerySelectionBehavior(gui);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.validate();
}
});
}
}
What happens is that, when I call neutralMode(), the “panels” collection happens to be empty (panels.size() equals zero). However when I call queryPatternMode() instead, the collection happens to have it's expected size (20 panels). But both methods are equals, and both are called from the same place!!!
What it could be??? Is there any possible explanation for that??
It definitely looks like a synchronisation issue. You should check how many threads are accessing the collection 'panels'.
It is just a stroke of luck that it works for you with queryPatternMode() all the time, and not with neutralMode(). On another fine day, it might be other way around.
A program that I've developed is crashing the JVM occasionally due to this bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8029516. Unfortunately the bug has not been resolved by Oracle and the bug report says that there are no known workarounds.
I've tried to modify the example code from the bug report by calling .register(sWatchService, eventKinds) in the KeyWatcher thread instead, by adding all pending register request to a list that I loop through in the KeyWatcher thread but it's still crashing. I'm guessing this just had the same effect as synchronizing on sWatchService (like the submitter of the bug report tried).
Can you think of any way to get around this?
From comments:
It appears that we have an issue with I/O cancellation when there is a pending ReadDirectoryChangesW outstanding.
The statement and example code indicate that the bug is triggered when:
There is a pending event that has not been consumed (it may or may not be visible to WatchService.poll() or WatchService.take())
WatchKey.cancel() is called on the key
This is a nasty bug with no universal workaround. The approach depends on the specifics of your application. Consider pooling watches to a single place so you don't need to call WatchKey.cancel(). If at one point the pool becomes too large, close the entire WatchService and start over. Something similar to.
public class FileWatcerService {
static Kind<?>[] allEvents = new Kind<?>[] {
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY
};
WatchService ws;
// Keep track of paths and registered listeners
Map<String, List<FileChangeListener>> listeners = new ConcurrentHashMap<String, List<FileChangeListener>>();
Map<WatchKey, String> keys = new ConcurrentHashMap<WatchKey, String>();
boolean toStop = false;
public interface FileChangeListener {
void onChange();
}
public void addFileChangeListener(String path, FileChangeListener l) {
if(!listeners.containsKey(path)) {
listeners.put(path, new ArrayList<FileChangeListener>());
keys.put(Paths.get(path).register(ws, allEvents), path);
}
listeners.get(path).add(l);
}
public void removeFileChangeListener(String path, FileChangeListener l) {
if(listeners.containsKey(path))
listeners.get(path).remove(l);
}
public void start() {
ws = FileSystems.getDefault().newWatchService();
new Thread(new Runnable() {
public void run() {
while(!toStop) {
WatchKey key = ws.take();
for(FileChangeListener l: listeners.get(keys.get(key)))
l.onChange();
}
}
}).start();
}
public void stop() {
toStop = true;
ws.close();
}
}
I've managed to create a workaround though it's somewhat ugly.
The bug is in JDK method WindowsWatchKey.invalidate() that releases native buffer while the subsequent calls may still access it. This one-liner fixes the problem by delaying buffer clean-up until GC.
Here is a compiled patch to JDK. In order to apply it add the following Java command-line flag:
-Xbootclasspath/p:jdk-8029516-patch.jar
If patching JDK is not an option in your case, there is still a workaround on the application level. It relies on the knowledge of Windows WatchService internal implementation.
public class JDK_8029516 {
private static final Field bufferField = getField("sun.nio.fs.WindowsWatchService$WindowsWatchKey", "buffer");
private static final Field cleanerField = getField("sun.nio.fs.NativeBuffer", "cleaner");
private static final Cleaner dummyCleaner = Cleaner.create(Thread.class, new Thread());
private static Field getField(String className, String fieldName) {
try {
Field f = Class.forName(className).getDeclaredField(fieldName);
f.setAccessible(true);
return f;
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
public static void patch(WatchKey key) {
try {
cleanerField.set(bufferField.get(key), dummyCleaner);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}
Call JDK_8029516.patch(watchKey) right after the key is registred, and it will prevent watchKey.cancel() from releasing the native buffer prematurely.
You might not be able to work around the problem itself but you could deal with the error and handle it. I don't know your specific situation but I could imagine the biggest issue is the crash of the whole JVM. Putting all in a try block does not work because you cannot catch a JVM crash.
Not knowing more about your project makes it difficult to suggest a good/acceptable solution, but maybe this could be an option: Do all the file watching stuff in a separate JVM process. From your main process start a new JVM (e.g. using ProcessBuilder.start()). When the process terminates (i.e. the newly started JVM crashes), restart it. Obviously you need to be able to recover, i.e. you need to keep track of what files to watch and you need to keep this data in your main process too.
Now the biggest remaining part is to implement some communication between the main process and the file watching process. This could be done using standard input/output of the file watching process or using a Socket/ServerSocket or some other mechanism.
I have an issue with my swing project , and after long time, I found that I have a concurrency issue. Nevertheless, I am clueless about concurrency issues ,and I just try to learn.
My project in nutshell is a database that gets connected to a JTable. When some operations such as enter, update, and delete happens, it affects both database which is derby and JTable at the same time.
I use SwingWorker and invokeLater in my code. Sometimes it works, but some other times it doesnot work.
my code is as follows
Note: I implement AbstractTableModel for my JTable which I advice I should have used DefualtTableModel.
the following code is for deleting part and I think I can apply the same functionality for other operations.
am I right about it?
private void deleteJBActionPerformed(java.awt.event.ActionEvent evt) {
deleteDB = new DeleteDB();
deleteDB.execute();
}
class DeleteDB extends SwingWorker<Void, Void> {
#Override
public Void doInBackground() {
try {
ed.deleteQuery(name1);
} catch (SQLException ex) {
Logger.getLogger(MyFrame.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("deleteing isuse is " + ex);
}
return null;
}
#Override
public void done() {
if (jTable1.getSelectedRow() >= 0) {
tm.removeRow(jTable1.getSelectedRow());
} else {
System.out.println("nothing is selected");
}
name.setText("");
tel.setText("");
ed.printData();
JOptionPane.showMessageDialog(null, "Task completed");
}
}
Please be kind and help to find out where my problem is.
Please inform me if you need more information from me.
Your basic code in the ActionListener is overly complicated.
Code invoked within a listener executes on the Event Dispatch Thread, so there is no need for the SwingUtilities.invokeLater()
for the same reason you don't need the synchronize block.
I would place all the code in the SwingWorker. That is, first you should delete the data from the database (since this is the functionality that is most likely to fail). If the deletete completes successfully then I would remove the row from the TableModel. So you could need to "publish" the row that you want to be deleted within the doInBackground() method. Then the code that executes in the process() method of the SwingWorker will automatically run on the EDT.
See Tasks That Have Intermediate Results for more information.
I seem to have a problem with SwingWorker.
I basically implemented the Java Example Code updating the UI from the propertyChange() method of my JFrame.
I also copied the sleep up to one second part in doInBackground.
This leaves me with a good update rate of setProgress within my Worker.
However the propertyChange Event is fired only once about every 10sec.
I know from the API that not every setProgress fires an event, and I'm ok with that, however it seems that this is kinda slow and too many events are lost.
When stepping through in a Debugger I get a better rate, ~once every 3 calls to setProgress
Any ideas why it is so slow?
Here are the parts of my Code:
public Void doInBackground() {
Random random = new Random();
setProgress(0);
float getSize=0,gotSize=0;
while (Sync.syncing) {
//Sleep for up to one second.
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException ignore) {
ignore.printStackTrace();
}
try{
getSize=Main.getSyncGet();
gotSize=Main.getSyncGot();
System.out.println("setProgress: "+(gotSize/getSize));
setProgress((int)((gotSize/(getSize))*100));
}catch(Exception e){
Main.LOGGER.log(Level.WARNING,"Error setting progress",e);
}
}
return null;
}
public void propertyChange(PropertyChangeEvent evt) {
if ("progress" == evt.getPropertyName()) {
jpb.setValue((Integer) evt.getNewValue());
}
}
Kind Regards
Jens
Your problem is quite possibly here:
System.out.println("setProgress: "+(gotSize/getSize));
setProgress((int)((gotSize/(getSize))*100));
Have you tested that the progress is actually being changed? A better println would be:
int value = (int)((gotSize/(getSize))*100);
System.out.println("setProgress: "+ value);
setProgress(value);
Now check to see if value is in fact changing.
Ooops, this is definitely wrong:
public void propertyChange(PropertyChangeEvent evt) {
if ("progress" == evt.getPropertyName()) {
jpb.setValue((Integer) evt.getNewValue());
}
}
Don't compare Strings using ==. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two objects are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of
if (fu == "bar") {
// do something
}
do,
if ("bar".equals(fu)) {
// do something
}
or,
if ("bar".equalsIgnoreCase(fu)) {
// do something
}
read SwingWorker, there are described possible scenarios, including code examples
setProgress(0); and setProgress((int)((gotSize/(getSize))*100)); must be called on EDT
output from folows methods could be done on EDT during doInBackground()
process()
publish()
setProgress()
most complex code example by #trashgod about PropertyChangeListener
for better help sooner post an SSCCE
You can try firing property changes manually:
setProgress(1);
firePropertyChange("progress", 0, 1);
I'm designing an app, which flicks through a series of pictures, like flicking through a photo album. Pretty standard stuff I'm sure.
Since the picture must be viewed for a few seconds before it automatically changes ot the next pic, I decided to ake a thread that shows the pic, waits couple of second and then moves on.
Picthread(ImageView Image1) {
this.image = Image1;
}
public void run(){
showPicture(image);
animal_array = new String[7];
while (counter < 7){
try{
int timer = 0;
while (timer < 2000){
sleep(500);
timer+=500;
}
image.post(new Runnable(){
public void run() {
showPicture(image);
}
});
}
catch (InterruptedException e) {
}
}
}
This actualy worked. showPictures is a very simple method that just chooses a picture and puts it on an ImageView. It isn't necessary to know about it for my problem.
At first itdidn't work, the logcat said I couldn't touch a view on a view heirarchy that wasnt created in this thread. I wasn't sure what that meant so I did the
image.post(...)
code. Which worked. My main question is: Why was this necesary? If you look at my above code, the first showPicture() method is not inside the image.post() code. But no exception is registered. I don't understand this, why isn't a post needed? But also why do I need to post, since Image is a class variable, and I thought could be viewed by all threads. I was happy it worked, but puzzled.
Please bare in mind, this is my first attempt at threading in Java on anything more than trivial textbook examples. SO I'm still pretty confused.
By the way, in the end I ditched the whole thread, and just did
new Thread(new Runnable() {
public void run() {...}
When doing "things" with the GUI you should always be on the GUI thread. That is what View.post(Runnable) does, ensuring that the gui thread does the work of the runnable.
Even though your showImage works once does not mean that it always works...