From 2026c60b1d43f86aed04591d73a18982855780d9 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Thu, 27 Mar 2008 00:28:06 +0000 Subject: [PATCH] * improved BackgroundTransferablePolicy * improved ChecksumComputationService * (... both don't "leak" threads anymore) --- .../net/sourceforge/filebot/FileFormat.java | 7 +- .../filebot/ui/panel/analyze/FileTree.java | 23 ++- ...y.java => FileTreeTransferablePolicy.java} | 19 ++- .../panel/rename/RenameListCellRenderer.java | 11 +- .../panel/rename/entry/AbstractFileEntry.java | 18 +- .../ui/panel/rename/entry/FileEntry.java | 13 +- .../ui/panel/rename/entry/TorrentEntry.java | 9 +- .../filebot/ui/panel/sfv/Checksum.java | 3 +- .../panel/sfv/ChecksumComputationService.java | 73 +++----- .../ui/panel/sfv/ChecksumTableModel.java | 10 +- .../filebot/ui/panel/sfv/SfvTable.java | 14 +- .../ui/panel/sfv/SfvTransferablePolicy.java | 6 +- .../BackgroundFileTransferablePolicy.java | 159 +++++++++--------- .../tuned/ByteBufferInputStream.java | 2 +- .../tuned/DefaultThreadFactory.java | 41 +++++ 15 files changed, 220 insertions(+), 188 deletions(-) rename source/net/sourceforge/filebot/ui/panel/analyze/{FileTreeTransferPolicy.java => FileTreeTransferablePolicy.java} (70%) create mode 100644 source/net/sourceforge/tuned/DefaultThreadFactory.java diff --git a/source/net/sourceforge/filebot/FileFormat.java b/source/net/sourceforge/filebot/FileFormat.java index 163abc25..f74b5e6c 100644 --- a/source/net/sourceforge/filebot/FileFormat.java +++ b/source/net/sourceforge/filebot/FileFormat.java @@ -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; diff --git a/source/net/sourceforge/filebot/ui/panel/analyze/FileTree.java b/source/net/sourceforge/filebot/ui/panel/analyze/FileTree.java index 14e16819..24d8e556 100644 --- a/source/net/sourceforge/filebot/ui/panel/analyze/FileTree.java +++ b/source/net/sourceforge/filebot/ui/panel/analyze/FileTree.java @@ -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(); } diff --git a/source/net/sourceforge/filebot/ui/panel/analyze/FileTreeTransferPolicy.java b/source/net/sourceforge/filebot/ui/panel/analyze/FileTreeTransferablePolicy.java similarity index 70% rename from source/net/sourceforge/filebot/ui/panel/analyze/FileTreeTransferPolicy.java rename to source/net/sourceforge/filebot/ui/panel/analyze/FileTreeTransferablePolicy.java index f543ca60..6d254cdf 100644 --- a/source/net/sourceforge/filebot/ui/panel/analyze/FileTreeTransferPolicy.java +++ b/source/net/sourceforge/filebot/ui/panel/analyze/FileTreeTransferablePolicy.java @@ -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 { +class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy { - 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 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 files) { for (File file : files) { - publish(getTree(file)); + DefaultMutableTreeNode node = getTree(file); + + if (Thread.currentThread().isInterrupted()) + return; + + publish(node); } } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/RenameListCellRenderer.java b/source/net/sourceforge/filebot/ui/panel/rename/RenameListCellRenderer.java index c22a7ee0..53209348 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/RenameListCellRenderer.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/RenameListCellRenderer.java @@ -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))); } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/entry/AbstractFileEntry.java b/source/net/sourceforge/filebot/ui/panel/rename/entry/AbstractFileEntry.java index 49f48910..b1125794 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/entry/AbstractFileEntry.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/entry/AbstractFileEntry.java @@ -4,25 +4,11 @@ package net.sourceforge.filebot.ui.panel.rename.entry; public abstract class AbstractFileEntry extends ListEntry { - 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(); } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/entry/FileEntry.java b/source/net/sourceforge/filebot/ui/panel/rename/entry/FileEntry.java index 6c069dce..c9101b9f 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/entry/FileEntry.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/entry/FileEntry.java @@ -10,7 +10,18 @@ import net.sourceforge.filebot.FileFormat; public class FileEntry extends AbstractFileEntry { 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()); } } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/entry/TorrentEntry.java b/source/net/sourceforge/filebot/ui/panel/rename/entry/TorrentEntry.java index 064999e9..d1496f8f 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/entry/TorrentEntry.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/entry/TorrentEntry.java @@ -10,6 +10,13 @@ import net.sourceforge.filebot.torrent.Torrent.Entry; public class TorrentEntry extends AbstractFileEntry { 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(); + } + } diff --git a/source/net/sourceforge/filebot/ui/panel/sfv/Checksum.java b/source/net/sourceforge/filebot/ui/panel/sfv/Checksum.java index 1b39fcc9..cec63685 100644 --- a/source/net/sourceforge/filebot/ui/panel/sfv/Checksum.java +++ b/source/net/sourceforge/filebot/ui/panel/sfv/Checksum.java @@ -43,9 +43,8 @@ public class Checksum { } - public Checksum(ChecksumComputationTask computationTask) { + protected Checksum(ChecksumComputationTask computationTask) { this.computationTask = computationTask; - this.computationTask.addPropertyChangeListener(new ComputationTaskPropertyChangeListener()); } diff --git a/source/net/sourceforge/filebot/ui/panel/sfv/ChecksumComputationService.java b/source/net/sourceforge/filebot/ui/panel/sfv/ChecksumComputationService.java index 47a6b91d..4bd069ad 100644 --- a/source/net/sourceforge/filebot/ui/panel/sfv/ChecksumComputationService.java +++ b/source/net/sourceforge/filebot/ui/panel/sfv/ChecksumComputationService.java @@ -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(), new ChecksumComputationThreadFactory()); + super(MINIMUM_POOL_SIZE, MINIMUM_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), 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); } } diff --git a/source/net/sourceforge/filebot/ui/panel/sfv/ChecksumTableModel.java b/source/net/sourceforge/filebot/ui/panel/sfv/ChecksumTableModel.java index b1c01125..7ebff6ca 100644 --- a/source/net/sourceforge/filebot/ui/panel/sfv/ChecksumTableModel.java +++ b/source/net/sourceforge/filebot/ui/panel/sfv/ChecksumTableModel.java @@ -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(); diff --git a/source/net/sourceforge/filebot/ui/panel/sfv/SfvTable.java b/source/net/sourceforge/filebot/ui/panel/sfv/SfvTable.java index 67e78757..d4db1906 100644 --- a/source/net/sourceforge/filebot/ui/panel/sfv/SfvTable.java +++ b/source/net/sourceforge/filebot/ui/panel/sfv/SfvTable.java @@ -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(); + } + }); } diff --git a/source/net/sourceforge/filebot/ui/panel/sfv/SfvTransferablePolicy.java b/source/net/sourceforge/filebot/ui/panel/sfv/SfvTransferablePolicy.java index 141810e8..f369457e 100644 --- a/source/net/sourceforge/filebot/ui/panel/sfv/SfvTransferablePolicy.java +++ b/source/net/sourceforge/filebot/ui/panel/sfv/SfvTransferablePolicy.java @@ -35,7 +35,6 @@ class SfvTransferablePolicy extends 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); + @Override public void handleTransferable(Transferable tr, boolean add) { @@ -33,39 +40,54 @@ public abstract class BackgroundFileTransferablePolicy 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 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 extends FileTransferab private class LoadFilesTask implements Runnable { - private List files; + private final List files; public LoadFilesTask(List files) { @@ -107,76 +129,21 @@ public abstract class BackgroundFileTransferablePolicy 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()); - } - - - 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 extends FileTransferab 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/ByteBufferInputStream.java b/source/net/sourceforge/tuned/ByteBufferInputStream.java index 8ac1ffbf..fc310ee2 100644 --- a/source/net/sourceforge/tuned/ByteBufferInputStream.java +++ b/source/net/sourceforge/tuned/ByteBufferInputStream.java @@ -9,7 +9,7 @@ import java.nio.ByteBuffer; public class ByteBufferInputStream extends InputStream { - private ByteBuffer buffer; + private final ByteBuffer buffer; public ByteBufferInputStream(ByteBuffer buffer) { diff --git a/source/net/sourceforge/tuned/DefaultThreadFactory.java b/source/net/sourceforge/tuned/DefaultThreadFactory.java new file mode 100644 index 00000000..d06b2d9c --- /dev/null +++ b/source/net/sourceforge/tuned/DefaultThreadFactory.java @@ -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; + } + +}