From 02057b3056ed0365d0243e0dba63a8bf1b2442fe Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Thu, 27 Mar 2008 21:44:48 +0000 Subject: [PATCH] * Simplyfied BackgroundTransferablePolicy again (no queuing again) * solves the "add after clear" concurrency problem when adding really lots of files --- .../filebot/ui/panel/analyze/FileTree.java | 20 +- .../filebot/ui/panel/sfv/SfvTable.java | 12 +- .../BackgroundFileTransferablePolicy.java | 181 +++++++----------- .../tuned/DefaultThreadFactory.java | 9 +- 4 files changed, 79 insertions(+), 143 deletions(-) diff --git a/source/net/sourceforge/filebot/ui/panel/analyze/FileTree.java b/source/net/sourceforge/filebot/ui/panel/analyze/FileTree.java index 24d8e556..a9565d00 100644 --- a/source/net/sourceforge/filebot/ui/panel/analyze/FileTree.java +++ b/source/net/sourceforge/filebot/ui/panel/analyze/FileTree.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -74,25 +73,15 @@ class FileTree extends FileBotTree { public void clear() { ((FileTreeTransferablePolicy) getTransferablePolicy()).reset(); - // there may still be some runnables from the transfer in the event queue, - // clear the model, after those runnables have finished, - // otherwise it may happen, that stuff is added, after the model has been cleared - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - FileTree.super.clear(); - contentChanged(); - } - }); - + super.clear(); + contentChanged(); } - void contentChanged() { + private void contentChanged() { synchronized (this) { if (postProcessor != null) - postProcessor.cancel(false); + postProcessor.cancel(true); postProcessor = new PostProcessor(); postProcessor.execute(); @@ -138,4 +127,5 @@ class FileTree extends FileBotTree { } } + } diff --git a/source/net/sourceforge/filebot/ui/panel/sfv/SfvTable.java b/source/net/sourceforge/filebot/ui/panel/sfv/SfvTable.java index d4db1906..e89570d3 100644 --- a/source/net/sourceforge/filebot/ui/panel/sfv/SfvTable.java +++ b/source/net/sourceforge/filebot/ui/panel/sfv/SfvTable.java @@ -12,7 +12,6 @@ import java.util.logging.Logger; import javax.swing.JTable; import javax.swing.ListSelectionModel; -import javax.swing.SwingUtilities; import javax.swing.event.TableModelEvent; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; @@ -93,16 +92,7 @@ class SfvTable extends JTable implements TransferablePolicySupport, Saveable { public void clear() { ((BackgroundFileTransferablePolicy) getTransferablePolicy()).reset(); - // there may still be some runnables from the transfer in the event queue, - // clear the model, after those runnables have finished, - // otherwise it may happen, that stuff is added, after the model has been cleared - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - ((ChecksumTableModel) getModel()).clear(); - } - }); + ((ChecksumTableModel) getModel()).clear(); } diff --git a/source/net/sourceforge/filebot/ui/transferablepolicies/BackgroundFileTransferablePolicy.java b/source/net/sourceforge/filebot/ui/transferablepolicies/BackgroundFileTransferablePolicy.java index 816ff8fc..e67c8f2e 100644 --- a/source/net/sourceforge/filebot/ui/transferablepolicies/BackgroundFileTransferablePolicy.java +++ b/source/net/sourceforge/filebot/ui/transferablepolicies/BackgroundFileTransferablePolicy.java @@ -3,101 +3,64 @@ package net.sourceforge.filebot.ui.transferablepolicies; import java.awt.datatransfer.Transferable; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; -import java.util.Arrays; import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; -import net.sourceforge.tuned.DefaultThreadFactory; +import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter; public abstract class BackgroundFileTransferablePolicy extends FileTransferablePolicy { public static final String LOADING_PROPERTY = "loading"; - private static final ThreadFactory backgroundTransferThreadFactory = new DefaultThreadFactory("BackgroundTransferPool", Thread.NORM_PRIORITY); - - private SingleThreadExecutor executor = null; - - private final AtomicInteger count = new AtomicInteger(0); + private BackgroundWorker worker = null; + @Override + public boolean accept(Transferable tr) { + if (isActive()) + return false; + + return super.accept(tr); + } + + @Override public void handleTransferable(Transferable tr, boolean add) { List files = getFilesFromTransferable(tr); - if (files == null) + if ((files == null) || files.isEmpty()) { return; - - if (!add) - clear(); - - execute(new LoadFilesTask(files)); - } - - - protected synchronized void execute(Runnable task) { - if (executor == null) { - executor = new SingleThreadExecutor(); } - executor.execute(task); - } - - - public boolean isActive() { - return count.get() > 0; - } - - - private synchronized void setActive(final boolean active) { - - SwingUtilities.invokeLater(new Runnable() { + synchronized (this) { + reset(); - @Override - public void run() { - propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, null, active); - } - }); - } - - - private synchronized void deactivate(boolean shutdownNow) { - if (executor != null) { - if (shutdownNow) { - executor.shutdownNow(); - } else { - executor.shutdown(); + if (!add) { + clear(); } - executor = null; + worker = new BackgroundWorker(files); + worker.addPropertyChangeListener(new BackgroundWorkerListener()); + worker.execute(); } - - count.set(0); + } + + + public synchronized boolean isActive() { + return (worker != null) && !worker.isDone(); } public synchronized void reset() { - deactivate(true); - setActive(false); - } - - - /** - * Sends data chunks to the process method. - * - * @param chunks - */ - protected final void publish(V... chunks) { - SwingUtilities.invokeLater(new ProcessChunksTask(chunks)); + if (isActive()) { + worker.cancel(true); + } } @@ -109,37 +72,62 @@ public abstract class BackgroundFileTransferablePolicy extends FileTransferab */ protected abstract void process(List chunks); + + /** + * Sends data chunks to the process method. + * + * @param chunks + */ + protected final void publish(V... chunks) { + worker.publishChunks(chunks); + } - private class LoadFilesTask implements Runnable { + + private class BackgroundWorker extends SwingWorker { private final List files; - public LoadFilesTask(List files) { + public BackgroundWorker(List files) { this.files = files; } @Override - public void run() { + protected Object doInBackground() { load(files); + + return null; } - } - + - private class ProcessChunksTask implements Runnable { - - private final V[] chunks; - - - public ProcessChunksTask(V[] chunks) { - this.chunks = chunks; + public void publishChunks(V... chunks) { + if (!isCancelled()) { + publish(chunks); + } } @Override - public void run() { - process(Arrays.asList(chunks)); + protected void process(List chunks) { + if (!isCancelled()) { + BackgroundFileTransferablePolicy.this.process(chunks); + } + } + } + + + private class BackgroundWorkerListener extends SwingWorkerPropertyChangeAdapter { + + @Override + public void started(PropertyChangeEvent evt) { + propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, null, true); + } + + + @Override + public void done(PropertyChangeEvent evt) { + propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, null, false); } } @@ -154,37 +142,4 @@ public abstract class BackgroundFileTransferablePolicy extends FileTransferab public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(propertyName, listener); } - - - private class SingleThreadExecutor extends ThreadPoolExecutor { - - public SingleThreadExecutor() { - super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), backgroundTransferThreadFactory); - } - - - @Override - public void execute(Runnable command) { - - if (count.getAndIncrement() <= 0) { - setActive(true); - } - - super.execute(command); - } - - - @Override - protected void afterExecute(Runnable r, Throwable t) { - super.afterExecute(r, t); - - if (count.decrementAndGet() <= 0) { - // shutdown executor - deactivate(false); - setActive(false); - } - } - - } - } diff --git a/source/net/sourceforge/tuned/DefaultThreadFactory.java b/source/net/sourceforge/tuned/DefaultThreadFactory.java index d06b2d9c..8a334a6e 100644 --- a/source/net/sourceforge/tuned/DefaultThreadFactory.java +++ b/source/net/sourceforge/tuned/DefaultThreadFactory.java @@ -23,6 +23,7 @@ public class DefaultThreadFactory implements ThreadFactory { public DefaultThreadFactory(String groupName, int priority, boolean daemon) { group = new ThreadGroup(groupName); group.setDaemon(daemon); + group.setMaxPriority(priority); this.daemon = daemon; this.priority = priority; @@ -30,12 +31,12 @@ public class DefaultThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) { - Thread t = new Thread(group, r, String.format("%s-thread-%d", group.getName(), threadNumber.incrementAndGet())); + Thread thread = new Thread(group, r, String.format("%s-thread-%d", group.getName(), threadNumber.incrementAndGet())); - t.setDaemon(daemon); - t.setPriority(priority); + thread.setDaemon(daemon); + thread.setPriority(priority); - return t; + return thread; } }