In Java, threads can be grouped together and associated with an instance of ThreadGroup. In this chapter, I’ll show you how to use some of the methods of ThreadGroup. At the end of the chapter, I’ll show you how to use the class ThreadViewer to visually display the status of all the threads running in the Java VM.
建構函式:ThreadGroup groupB = new ThreadGroup(“groupB”);ThreadGroup groupD = new ThreadGroup(groupC, “groupD”);//父線程組
getName()To retrieve the name of a particular group, the getName() method is used.String groupName = group.getName(); 返回線程組名
Thread的建構函式New Thread objects default to be in the same thread group as the thread that does the constructionThread threadZ = new Thread(target); 新線程預設為在當前線程組中 If a new thread should be in another group, the desired thread group can be passed to the constructor for Thread.Thread threadZ = new Thread(groupC, target); 也可以指定所屬的線程組
getParent()If you need to know which thread group a particular thread group belongs to, you can use the getParent() method on ThreadGroup.
ThreadGroup parentOfGroupD = groupD.getParent(); If getParent() is invoked on the root thread group, null is returned. In the VM, only one instance of ThreadGroup does not have a parent group, and that is the root group. 獲得線程組的父線程組,如果根線程組調用此方法返回null。Java虛擬機器中只有一個根線程。
activeGroupCount()/enumerate(ThreadGroup[])The activeGroupCount() method returns the number of active thread groups in a particular ThreadGroup
and all of its subgroups. Keep in mind that this can be dynamically changing, but it’s an accurate snapshot at a moment in time. 返回調用線程組及其子線程組中所有活動線程組數,只是某個時刻的值。 To get a reference to all of the groups and subgroups of a ThreadGroup, the enumerate(ThreadGroup[]) method can be used. If you don’t want to include a recursive search of the subgroups, use enumerate(ThreadGroup[], false) instead. Both methods return the number of groups copied into the array that is passed. If the array is not big enough, the extra groups are silently ignored. To get an idea of how big the destination array needs to be, you can use the value returned from activeGroupCount(). This code tries to capture all of the groups and subgroups of group: enumerate(ThreadGroup[])返回此線程組中所有線程組,包括子線程組中的線程組enumerate(ThreadGroup[], false)返回此線程組中所有線程組,不包括子線程組中的線程組 兩個方法將線程組通過參數返回,如果參數中給的線程組不夠大,則忽略餘下的,所以,應該盡量大。 下面這端代碼返回線程組中的所有線程組數組,真實大小ThreadGroup group = // ...int estimatedSize = 2 * group.
activeGroupCount();ThreadGroup[] dest = new ThreadGroup[estimatedSize];int actualSize = group.
enumerate(dest); The count returned from activeGroupCount() is doubled in an attempt to be sure that the destination array is large enough. Based on estimatedSize, a destination array for the groups is allocated and referred to by dest. The enumerate(ThreadGroup[]) method copies up to dest.length groups into dest. The number of groups copied is returned and stored in actualSize. If actualSize is equal to dest.length, there is a good chance that dest was not big enough. Generally, actualSize is less than dest.length and indicates the number of valid groups in dest.
getThreadGroup()If you need to know which thread group a thread belongs to, you can use the getThreadGroup() method on Thread.ThreadGroup groupForThreadX = threadX.getThreadGroup(); groupForThreadX is a reference to the ThreadGroup that threadX belongs to. If a thread is no longer alive, getThreadGroup() returns null instead of a ThreadGroup.To determine which thread group the thread executing a block of code belongs to, use:ThreadGroup group = Thread.currentThread().getThreadGroup();
activeCount()The activeCount() method returns the number of active threads in a particular ThreadGroup
and all of its subgroups. Keep in mind that this can be dynamically changing, as new threads might be created and existing threads might be dying. To get a reference to all of the threads in a ThreadGroup and all of its subgroups, the enumerate(Thread[]) method can be used. If you don’t want to include a recursive search of the subgroups, use enumerate(Thread[], false) instead. Both methods return the number of threads copied into the passed array. If the array is not big enough, the extra threads are silently ignored. To get an idea of how big the destination array needs to be, you can use the value returned from activeCount(). This code tries to capture all of the threads in group and its subgroups: ThreadGroup group = // ...int estimatedSize = 2 * group.
activeCount();Thread[] dest = new Thread[estimatedSize];int actualSize = group.
enumerate(dest); 同上,返回線程組中所有線程。
checkAccess()The checkAccess() method of ThreadGroup is called internally by many of the other ThreadGroup methods. It checks to see if a SecurityManager exists for a VM. By default, applications do not have a SecurityManager installed. Applets, on the other hand, might ave one. If a SecurityManager exists and it determines that a particular thread is not permitted to take an action, it throws a SecurityException. SecurityException is a subclass of RuntimeException, so try/catch blocks are typically not used. If no SecurityManager is installed, or if the SecurityManager approves of the access, checkAccess() silently returns. 檢查虛擬機器中是否包括SecurityManager,一般都沒有,像Applet,可能會存在。如果有,且某個線程不允許訪問,此方法會拋出SecurityException異常,如果沒有,或者允許訪問,則直接返回。
setMaxPriority() / getMaxPriority()The setMaxPriority() method sets the maximum priority that all threads in a particular thread group and all of its subgroups can have. Threads that are already running at a higher priority are not affected. This method has an effect when new threads are constructed or when the setPriority() method of Thread is invoked. If setPriority() is called with a priority higher than the maximum allowed for the group that a thread is in, the priority is silently lowered to the maximum allowed. The getMaxPriority() method returns the current maximum priority permitted for threads in a particular thread group. 設定線程組中所有線程(包括子線程組中的線程)的最大優先順序。不影響現有的更高優先順序的線程,建立線程setPriority更高的優先順序時會有影響,會直接將其優先順序降為線程組的最大優先順序。
interrupt()The interrupt() method of ThreadGroup can be used to signal an interrupt to all the threads in the group and subgroups. This method can be useful if several threads have been spawned to handle a task, and it’s time to signal all of them to shut down. (See Chapter 5, “Gracefully Stopping Threads,” for more on signaling threads to die by interrupting them.) 線程組的interrupt()會中止此線程組中的所有線程。
Deprecated --stop(), suspend(),resume()Class ThreadViewerThe class ThreadViewer (see Listing 10.1) graphically displays all of the threads currently running in the Java VM. It automatically refreshes itself every 5 seconds to keep current. ThreadViewer can be a handy tool to have around during the development and debugging of multithreaded applications. 用圖表顯示當前java虛擬機器種的所有線程及其狀態。5秒鐘重新整理一次保持更新。
ThreadViewerTableModel.java/* * Created on 2005-7-18 * * Java Thread Programming - Paul Hyde * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 * */package org.tju.msnrl.jonathan.thread.chapter9; import java.awt.*;import java.lang.reflect.*;import javax.swing.*;import javax.swing.table.*; /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo * blog.yesky.net/jonathanundersun * * Enjoy Life with Sun! * */public class ThreadViewerTableModel extends AbstractTableModel { private Object dataLock; private int rowCount; private Object[][] cellData; private Object[][] pendingCellData; /*列資訊*/ private final int columnCount; private final String[] columnName; private final Class[] columnClass; /*自運行對象及控制變數*/ private Thread internalThread; private volatile boolean noStopRequested; /*建構函式*/ public ThreadViewerTableModel(){ rowCount = 0; cellData = new Object[0][0]; String[] names = {"Priority","Alive","Daemon","Interrupted","ThreadGroup","Thread Name"}; columnName = names; Class[] classes = { Integer.class,Boolean.class, Boolean.class,Boolean.class, String.class,String.class}; columnClass = classes; columnCount = columnName.length; /*控制並發訪問*/ dataLock = new Object(); noStopRequested = true; Runnable r = new Runnable(){ public void run(){ try{ runWork(); }catch(Exception e){ e.printStackTrace(); } } }; internalThread = new Thread(r,"ThreadViewer"); internalThread.setPriority(Thread.MAX_PRIORITY - 2); internalThread.setDaemon(true);//守護線程,隨著main線程結束而結束 internalThread.start(); } private void runWork(){ Runnable transferPending = new Runnable(){ public void run(){ transferPendingCellData(); /*AbstractTableModel類的方法,更新table*/ fireTableDataChanged(); } }; while(noStopRequested){ try{ createPendingCellData(); SwingUtilities.invokeAndWait(transferPending); Thread.sleep(5000); }catch(InvocationTargetException e1){ e1.printStackTrace(); stopRequest(); }catch(InterruptedException e2){ Thread.currentThread().interrupt(); } } } private void createPendingCellData(){ Thread[] thread = findAllThreads(); Object[][] cell = new Object[thread.length][columnCount]; for(int i = 0; i < thread.length; i++){ Thread t = thread[i]; Object[] rowCell = cell[i]; rowCell[0] = new Integer(t.getPriority()); rowCell[1] = new Boolean(t.isAlive()); rowCell[2] = new Boolean(t.isDaemon()); rowCell[3] = new Boolean(t.isInterrupted()); rowCell[4] = t.getThreadGroup().getName(); rowCell[5] = t.getName(); } synchronized(dataLock){ pendingCellData = cell; } } private static Thread[] findAllThreads(){ ThreadGroup group = Thread.currentThread().getThreadGroup(); ThreadGroup topGroup = group; /*迴圈獲得根線程組*/ while(group != null){ topGroup = group; group = group.getParent(); } int estimatedSize = topGroup.activeCount() * 2; Thread[] slackList = new Thread[estimatedSize]; int actualSize = topGroup.enumerate(slackList); /*銬到實際大小尺寸的list*/ Thread[] list = new Thread[actualSize]; System.arraycopy(slackList,0,list,0,actualSize); return list; } private void transferPendingCellData(){ synchronized(dataLock){ cellData = pendingCellData; rowCount = cellData.length; } } public void stopRequest(){ noStopRequested = false; internalThread.interrupt(); } public boolean isAlive(){ return internalThread.isAlive(); } /* (non-Javadoc) * @see javax.swing.table.TableModel#getColumnCount() */ public int getColumnCount() { // TODO Auto-generated method stub return columnCount; } /* (non-Javadoc) * @see javax.swing.table.TableModel#getRowCount() */ public int getRowCount() { // TODO Auto-generated method stub return rowCount; } /* (non-Javadoc) * @see javax.swing.table.TableModel#getValueAt(int, int) */ public Object getValueAt(int rowIndex, int columnIndex) { // TODO Auto-generated method stub return cellData[rowIndex][columnIndex]; } public Class getColumnClass(int columnIndex){ return columnClass[columnIndex]; } public String getColumnName(int columnIndex){ return columnName[columnIndex]; } }
ThreadViewer.java/* * Created on 2005-7-18 * * Java Thread Programming - Paul Hyde * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 * */package org.tju.msnrl.jonathan.thread.chapter9; import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.table.*; /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo * blog.yesky.net/jonathanundersun * * Enjoy Life with Sun! * */public class ThreadViewer extends JPanel{ private ThreadViewerTableModel tableModel; public ThreadViewer(){ tableModel = new ThreadViewerTableModel(); JTable table = new JTable(tableModel); table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); TableColumnModel colModel = table.getColumnModel(); int numColumns = colModel.getColumnCount(); /*設定列寬*/ for(int i = 0; i < numColumns - 1; i++){ TableColumn col = colModel.getColumn(i); col.sizeWidthToFit(); col.setPreferredWidth(col.getWidth() + 5); col.setMaxWidth(col.getWidth() + 5); } JScrollPane sp = new JScrollPane(table); setLayout(new BorderLayout()); add(sp,BorderLayout.CENTER); } public static JFrame createFramedInstance(){ final ThreadViewer viewer = new ThreadViewer(); final JFrame f = new JFrame("Thread Viewer"); f.addWindowListener( new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.out.println("windowclosing ... "); f.setVisible(false); f.dispose(); viewer.dispose(); } } ); f.setContentPane(viewer); f.setSize(500,300); f.setVisible(true); return f; } public void dispose(){ tableModel.stopRequest(); } protected void finalize() throws Throwable{ dispose(); } public static void main(String[] args){ JFrame f = ThreadViewer.createFramedInstance(); f.addWindowListener( new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.out.println("system.exit(0)"); System.exit(0); } } ); Object lock = new Object(); synchronized(lock){ try{ lock.wait(); }catch(InterruptedException x){ } } } }