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 construction
Thread 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 ThreadViewer
The 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){
}
}
}
}