* Simplyfied BackgroundTransferablePolicy again (no queuing again)

* solves the "add after clear" concurrency problem when adding really lots of files
This commit is contained in:
Reinhard Pointner 2008-03-27 21:44:48 +00:00
parent 2026c60b1d
commit 02057b3056
4 changed files with 79 additions and 143 deletions

View File

@ -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 {
}
}
}

View File

@ -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();
}

View File

@ -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<V> extends FileTransferablePolicy {
public static final String LOADING_PROPERTY = "loading";
private static final ThreadFactory backgroundTransferThreadFactory = new DefaultThreadFactory("BackgroundTransferPool", Thread.NORM_PRIORITY);
private BackgroundWorker worker = null;
private SingleThreadExecutor executor = null;
private final AtomicInteger count = new AtomicInteger(0);
@Override
public boolean accept(Transferable tr) {
if (isActive())
return false;
return super.accept(tr);
}
@Override
public void handleTransferable(Transferable tr, boolean add) {
List<File> 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);
}
synchronized (this) {
reset();
public boolean isActive() {
return count.get() > 0;
}
private synchronized void setActive(final boolean active) {
SwingUtilities.invokeLater(new Runnable() {
@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);
}
}
@ -110,36 +73,61 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
protected abstract void process(List<V> chunks);
private class LoadFilesTask implements Runnable {
/**
* Sends data chunks to the process method.
*
* @param chunks
*/
protected final void publish(V... chunks) {
worker.publishChunks(chunks);
}
private class BackgroundWorker extends SwingWorker<Object, V> {
private final List<File> files;
public LoadFilesTask(List<File> files) {
public BackgroundWorker(List<File> 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<V> 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<V> 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<Runnable>(), 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);
}
}
}
}

View File

@ -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;
}
}