* improved BackgroundTransferablePolicy
* improved ChecksumComputationService * (... both don't "leak" threads anymore)
This commit is contained in:
parent
ee6dc82d50
commit
2026c60b1d
|
@ -108,12 +108,7 @@ public class FileFormat {
|
|||
if (file.isDirectory())
|
||||
return "Folder";
|
||||
|
||||
return getFileType(file.getName());
|
||||
}
|
||||
|
||||
|
||||
public static String getFileType(String name) {
|
||||
String extension = getExtension(name, false);
|
||||
String extension = getExtension(file.getName(), false);
|
||||
|
||||
if (!extension.isEmpty())
|
||||
return extension;
|
||||
|
|
|
@ -10,6 +10,7 @@ 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;
|
||||
|
@ -31,7 +32,7 @@ class FileTree extends FileBotTree {
|
|||
|
||||
|
||||
public FileTree() {
|
||||
FileTreeTransferPolicy transferPolicy = new FileTreeTransferPolicy(this);
|
||||
FileTreeTransferablePolicy transferPolicy = new FileTreeTransferablePolicy(this);
|
||||
transferPolicy.addPropertyChangeListener(LOADING_PROPERTY, new LoadingPropertyChangeListener());
|
||||
|
||||
setTransferablePolicy(transferPolicy);
|
||||
|
@ -71,16 +72,20 @@ class FileTree extends FileBotTree {
|
|||
|
||||
@Override
|
||||
public void clear() {
|
||||
FileTreeTransferPolicy transferPolicy = ((FileTreeTransferPolicy) getTransferablePolicy());
|
||||
boolean loading = transferPolicy.isActive();
|
||||
((FileTreeTransferablePolicy) getTransferablePolicy()).reset();
|
||||
|
||||
if (loading) {
|
||||
transferPolicy.cancelAll();
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -6,17 +6,18 @@ import java.io.File;
|
|||
import java.util.List;
|
||||
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
|
||||
import net.sourceforge.filebot.FileBotUtil;
|
||||
import net.sourceforge.filebot.ui.transferablepolicies.BackgroundFileTransferablePolicy;
|
||||
|
||||
|
||||
class FileTreeTransferPolicy extends BackgroundFileTransferablePolicy<DefaultMutableTreeNode> {
|
||||
class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<DefaultMutableTreeNode> {
|
||||
|
||||
private FileTree tree;
|
||||
private final FileTree tree;
|
||||
|
||||
|
||||
public FileTreeTransferPolicy(FileTree tree) {
|
||||
public FileTreeTransferablePolicy(FileTree tree) {
|
||||
this.tree = tree;
|
||||
}
|
||||
|
||||
|
@ -35,18 +36,26 @@ class FileTreeTransferPolicy extends BackgroundFileTransferablePolicy<DefaultMut
|
|||
|
||||
@Override
|
||||
protected void process(List<DefaultMutableTreeNode> chunks) {
|
||||
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
|
||||
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
|
||||
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
|
||||
|
||||
for (DefaultMutableTreeNode node : chunks) {
|
||||
root.add(node);
|
||||
}
|
||||
|
||||
model.reload(root);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void load(List<File> files) {
|
||||
for (File file : files) {
|
||||
publish(getTree(file));
|
||||
DefaultMutableTreeNode node = getTree(file);
|
||||
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
|
||||
publish(node);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ import javax.swing.ListModel;
|
|||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.AbstractFileEntry;
|
||||
import net.sourceforge.filebot.ui.panel.rename.entry.FileEntry;
|
||||
import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer;
|
||||
|
||||
|
||||
|
@ -50,8 +50,8 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
|||
public void configureListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
super.configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
|
||||
if ((list.getModel() == files) && (value instanceof AbstractFileEntry<?>)) {
|
||||
AbstractFileEntry<?> entry = (AbstractFileEntry<?>) value;
|
||||
if ((list.getModel() == files) && (value instanceof FileEntry)) {
|
||||
FileEntry entry = (FileEntry) value;
|
||||
|
||||
extension.setText(entry.getType());
|
||||
extension.setVisible(true);
|
||||
|
@ -86,7 +86,7 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
|||
private class ExtensionLabel extends JLabel {
|
||||
|
||||
private final Insets margin = new Insets(0, 10, 0, 0);
|
||||
private final Insets padding = new Insets(1, 6, 1, 5);
|
||||
private final Insets padding = new Insets(0, 6, 0, 5);
|
||||
private final int arc = 10;
|
||||
|
||||
private Color gradientBeginColor = new Color(0xFFCC00);
|
||||
|
@ -97,7 +97,7 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
|||
|
||||
public ExtensionLabel() {
|
||||
setOpaque(false);
|
||||
setForeground(new Color(42, 42, 42));
|
||||
setForeground(new Color(0x141414));
|
||||
|
||||
setBorder(new CompoundBorder(new EmptyBorder(margin), new EmptyBorder(padding)));
|
||||
}
|
||||
|
@ -120,7 +120,6 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
|||
g2d.setPaint(getForeground());
|
||||
|
||||
Rectangle2D textBounds = g2d.getFontMetrics().getStringBounds(getText(), g2d);
|
||||
|
||||
g2d.drawString(getText(), (float) (shape.getCenterX() - textBounds.getX() - (textBounds.getWidth() / 2f)), (float) (shape.getCenterY() - textBounds.getY() - (textBounds.getHeight() / 2)));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,25 +4,11 @@ package net.sourceforge.filebot.ui.panel.rename.entry;
|
|||
|
||||
public abstract class AbstractFileEntry<T> extends ListEntry<T> {
|
||||
|
||||
private final long length;
|
||||
|
||||
private final String type;
|
||||
|
||||
|
||||
public AbstractFileEntry(String name, T value, String type, long length) {
|
||||
public AbstractFileEntry(String name, T value) {
|
||||
super(name, value);
|
||||
this.length = length;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public abstract long getLength();
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,18 @@ import net.sourceforge.filebot.FileFormat;
|
|||
public class FileEntry extends AbstractFileEntry<File> {
|
||||
|
||||
public FileEntry(File file) {
|
||||
super(FileFormat.getFileName(file), file, FileFormat.getFileType(file), file.length());
|
||||
super(FileFormat.getFileName(file), file);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return getValue().length();
|
||||
}
|
||||
|
||||
|
||||
public String getType() {
|
||||
return FileFormat.getFileType(getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,13 @@ import net.sourceforge.filebot.torrent.Torrent.Entry;
|
|||
public class TorrentEntry extends AbstractFileEntry<Torrent.Entry> {
|
||||
|
||||
public TorrentEntry(Entry value) {
|
||||
super(FileFormat.getNameWithoutExtension(value.getName()), value, FileFormat.getFileType(value.getName()), value.getLength());
|
||||
super(FileFormat.getNameWithoutExtension(value.getName()), value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return getValue().getLength();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,9 +43,8 @@ public class Checksum {
|
|||
}
|
||||
|
||||
|
||||
public Checksum(ChecksumComputationTask computationTask) {
|
||||
protected Checksum(ChecksumComputationTask computationTask) {
|
||||
this.computationTask = computationTask;
|
||||
|
||||
this.computationTask.addPropertyChangeListener(new ComputationTaskPropertyChangeListener());
|
||||
}
|
||||
|
||||
|
|
|
@ -18,12 +18,16 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.sourceforge.tuned.DefaultThreadFactory;
|
||||
|
||||
|
||||
public class ChecksumComputationService {
|
||||
|
||||
public static final String ACTIVE_PROPERTY = "ACTIVE_PROPERTY";
|
||||
public static final String REMAINING_TASK_COUNT_PROPERTY = "REMAINING_TASK_COUNT_PROPERTY";
|
||||
|
||||
private static final ThreadFactory checksumComputationThreadFactory = new DefaultThreadFactory("ChecksumComputationPool", Thread.MIN_PRIORITY);
|
||||
|
||||
private static final ChecksumComputationService service = new ChecksumComputationService();
|
||||
|
||||
|
||||
|
@ -44,22 +48,35 @@ public class ChecksumComputationService {
|
|||
}
|
||||
|
||||
|
||||
public ChecksumComputationTask submit(File file, File workerQueueKey) {
|
||||
public Checksum getChecksum(File file, File workerQueueKey) {
|
||||
ChecksumComputationTask task = new ChecksumComputationTask(file);
|
||||
Checksum checksum = new Checksum(task);
|
||||
|
||||
getExecutor(workerQueueKey).execute(task);
|
||||
|
||||
return task;
|
||||
return checksum;
|
||||
}
|
||||
|
||||
|
||||
public void cancelAll() {
|
||||
public void reset() {
|
||||
deactivate(true);
|
||||
}
|
||||
|
||||
|
||||
private void deactivate(boolean shutdownNow) {
|
||||
synchronized (executors) {
|
||||
for (ChecksumComputationExecutor executor : executors.values()) {
|
||||
executor.shutdownNow();
|
||||
if (shutdownNow) {
|
||||
executor.shutdownNow();
|
||||
} else {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
setActive(false);
|
||||
executors.clear();
|
||||
|
||||
activeSessionTaskCount.set(0);
|
||||
remainingTaskCount.set(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +125,7 @@ public class ChecksumComputationService {
|
|||
|
||||
|
||||
public ChecksumComputationExecutor() {
|
||||
super(MINIMUM_POOL_SIZE, MINIMUM_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new ChecksumComputationThreadFactory());
|
||||
super(MINIMUM_POOL_SIZE, MINIMUM_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), checksumComputationThreadFactory);
|
||||
}
|
||||
|
||||
|
||||
|
@ -191,6 +208,7 @@ public class ChecksumComputationService {
|
|||
super.afterExecute(r, t);
|
||||
|
||||
if (remainingTaskCount.decrementAndGet() <= 0) {
|
||||
deactivate(false);
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
|
@ -200,15 +218,6 @@ public class ChecksumComputationService {
|
|||
|
||||
|
||||
private void setActive(boolean active) {
|
||||
if (!active) {
|
||||
activeSessionTaskCount.set(0);
|
||||
remainingTaskCount.set(0);
|
||||
|
||||
synchronized (executors) {
|
||||
executors.clear();
|
||||
}
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(new FirePropertyChangeRunnable(ACTIVE_PROPERTY, active));
|
||||
}
|
||||
|
||||
|
@ -231,46 +240,18 @@ public class ChecksumComputationService {
|
|||
private class FirePropertyChangeRunnable implements Runnable {
|
||||
|
||||
private final String property;
|
||||
private final Object oldValue;
|
||||
private final Object newValue;
|
||||
|
||||
|
||||
public FirePropertyChangeRunnable(String property, Object oldValue, Object newValue) {
|
||||
this.property = property;
|
||||
this.oldValue = oldValue;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
|
||||
public FirePropertyChangeRunnable(String property, Object newValue) {
|
||||
this(property, null, newValue);
|
||||
this.property = property;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
propertyChangeSupport.firePropertyChange(property, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class ChecksumComputationThreadFactory implements ThreadFactory {
|
||||
|
||||
private static final AtomicInteger poolNumber = new AtomicInteger(0);
|
||||
|
||||
private final ThreadGroup group = new ThreadGroup("ChecksumComputationPool");
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(0);
|
||||
|
||||
private final String namePrefix = String.format("%s-%d-thread-", group.getName(), poolNumber.incrementAndGet());
|
||||
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(group, r, namePrefix + threadNumber.incrementAndGet(), 0);
|
||||
|
||||
t.setDaemon(false);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
|
||||
return t;
|
||||
propertyChangeSupport.firePropertyChange(property, null, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -147,15 +147,7 @@ class ChecksumTableModel extends AbstractTableModel {
|
|||
|
||||
|
||||
public synchronized void clear() {
|
||||
|
||||
// stop any running computations
|
||||
for (ChecksumRow row : rows) {
|
||||
for (Checksum checksum : row.getChecksums()) {
|
||||
checksum.cancelComputationTask();
|
||||
}
|
||||
}
|
||||
|
||||
ChecksumComputationService.getService().cancelAll();
|
||||
ChecksumComputationService.getService().reset();
|
||||
|
||||
checksumColumnRoots.clear();
|
||||
rows.clear();
|
||||
|
|
|
@ -12,6 +12,7 @@ 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;
|
||||
|
@ -90,9 +91,18 @@ class SfvTable extends JTable implements TransferablePolicySupport, Saveable {
|
|||
|
||||
|
||||
public void clear() {
|
||||
((BackgroundFileTransferablePolicy<?>) getTransferablePolicy()).cancelAll();
|
||||
((BackgroundFileTransferablePolicy<?>) getTransferablePolicy()).reset();
|
||||
|
||||
((ChecksumTableModel) getModel()).clear();
|
||||
// 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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||
|
||||
@Override
|
||||
protected void clear() {
|
||||
cancelAll();
|
||||
tableModel.clear();
|
||||
}
|
||||
|
||||
|
@ -71,7 +70,7 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||
File compareFile = new File(compareColumnRoot, filename);
|
||||
|
||||
if (compareFile.exists()) {
|
||||
publish(new ChecksumTableModel.Entry(filename, new Checksum(ChecksumComputationService.getService().submit(compareFile, compareColumnRoot)), compareColumnRoot));
|
||||
publish(new ChecksumTableModel.Entry(filename, ChecksumComputationService.getService().getChecksum(compareFile, compareColumnRoot), compareColumnRoot));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,8 +122,7 @@ class SfvTransferablePolicy extends BackgroundFileTransferablePolicy<ChecksumTab
|
|||
load(f, columnRoot, newPrefix);
|
||||
}
|
||||
} else if (file.isFile()) {
|
||||
publish(new ChecksumTableModel.Entry(prefix + file.getName(), new Checksum(ChecksumComputationService.getService().submit(file, columnRoot)), columnRoot));
|
||||
publish(new ChecksumTableModel.Entry(prefix + file.getName(), ChecksumComputationService.getService().getChecksum(file, columnRoot), columnRoot));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,19 +9,26 @@ 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 net.sourceforge.tuned.DefaultThreadFactory;
|
||||
|
||||
|
||||
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 SingleThreadExecutor executor = null;
|
||||
|
||||
private final AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
|
||||
@Override
|
||||
public void handleTransferable(Transferable tr, boolean add) {
|
||||
|
@ -33,39 +40,54 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||
if (!add)
|
||||
clear();
|
||||
|
||||
submit(new LoadFilesTask(files));
|
||||
execute(new LoadFilesTask(files));
|
||||
}
|
||||
|
||||
|
||||
protected void submit(Runnable task) {
|
||||
synchronized (this) {
|
||||
if (executor == null) {
|
||||
executor = new SingleThreadExecutor();
|
||||
}
|
||||
protected synchronized void execute(Runnable task) {
|
||||
if (executor == null) {
|
||||
executor = new SingleThreadExecutor();
|
||||
}
|
||||
|
||||
executor.submit(task);
|
||||
executor.execute(task);
|
||||
}
|
||||
|
||||
|
||||
public boolean isActive() {
|
||||
synchronized (this) {
|
||||
if (executor == null)
|
||||
return false;
|
||||
|
||||
return executor.isActive();
|
||||
}
|
||||
return count.get() > 0;
|
||||
}
|
||||
|
||||
|
||||
public void cancelAll() {
|
||||
synchronized (this) {
|
||||
if (executor != null) {
|
||||
// interrupt all threads
|
||||
executor.shutdownNow();
|
||||
executor = null;
|
||||
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();
|
||||
}
|
||||
|
||||
executor = null;
|
||||
}
|
||||
|
||||
count.set(0);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void reset() {
|
||||
deactivate(true);
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,7 +97,7 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||
* @param chunks
|
||||
*/
|
||||
protected final void publish(V... chunks) {
|
||||
SwingUtilities.invokeLater(new ProcessChunksTask(chunks, Thread.currentThread()));
|
||||
SwingUtilities.invokeLater(new ProcessChunksTask(chunks));
|
||||
}
|
||||
|
||||
|
||||
|
@ -90,7 +112,7 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||
|
||||
private class LoadFilesTask implements Runnable {
|
||||
|
||||
private List<File> files;
|
||||
private final List<File> files;
|
||||
|
||||
|
||||
public LoadFilesTask(List<File> files) {
|
||||
|
@ -107,76 +129,21 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||
|
||||
private class ProcessChunksTask implements Runnable {
|
||||
|
||||
private V[] chunks;
|
||||
private Thread publisher;
|
||||
private final V[] chunks;
|
||||
|
||||
|
||||
public ProcessChunksTask(V[] chunks, Thread publisher) {
|
||||
public ProcessChunksTask(V[] chunks) {
|
||||
this.chunks = chunks;
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!publisher.isInterrupted() && publisher.isAlive()) {
|
||||
process(Arrays.asList(chunks));
|
||||
}
|
||||
process(Arrays.asList(chunks));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class SingleThreadExecutor extends ThreadPoolExecutor {
|
||||
|
||||
private final AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
|
||||
public SingleThreadExecutor() {
|
||||
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
}
|
||||
|
||||
|
||||
public boolean isActive() {
|
||||
return count.get() > 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
|
||||
if (count.getAndIncrement() <= 0) {
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, false, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
super.execute(command);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
super.afterExecute(r, t);
|
||||
|
||||
if (count.decrementAndGet() <= 0) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
propertyChangeSupport.firePropertyChange(LOADING_PROPERTY, true, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
|
||||
|
||||
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
|
||||
|
@ -188,4 +155,36 @@ public abstract class BackgroundFileTransferablePolicy<V> extends FileTransferab
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.nio.ByteBuffer;
|
|||
|
||||
public class ByteBufferInputStream extends InputStream {
|
||||
|
||||
private ByteBuffer buffer;
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
|
||||
public ByteBufferInputStream(ByteBuffer buffer) {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
package net.sourceforge.tuned;
|
||||
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
||||
public class DefaultThreadFactory implements ThreadFactory {
|
||||
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(0);
|
||||
private final ThreadGroup group;
|
||||
|
||||
private final int priority;
|
||||
private final boolean daemon;
|
||||
|
||||
|
||||
public DefaultThreadFactory(String name, int priority) {
|
||||
this(name, priority, false);
|
||||
}
|
||||
|
||||
|
||||
public DefaultThreadFactory(String groupName, int priority, boolean daemon) {
|
||||
group = new ThreadGroup(groupName);
|
||||
group.setDaemon(daemon);
|
||||
|
||||
this.daemon = daemon;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(group, r, String.format("%s-thread-%d", group.getName(), threadNumber.incrementAndGet()));
|
||||
|
||||
t.setDaemon(daemon);
|
||||
t.setPriority(priority);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue