|
Java example source code file (ThreadTab.java)
This example Java source code file (ThreadTab.java) is included in the alvinalexander.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Learn more about this Java project at its project page.
The ThreadTab.java Java example source code
/*
* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.tools.jconsole;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.management.*;
import java.lang.reflect.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.List;
import static sun.tools.jconsole.Utilities.*;
@SuppressWarnings("serial")
class ThreadTab extends Tab implements ActionListener, DocumentListener, ListSelectionListener {
PlotterPanel threadMeter;
TimeComboBox timeComboBox;
JTabbedPane threadListTabbedPane;
DefaultListModel<Long> listModel;
JTextField filterTF;
JLabel messageLabel;
JSplitPane threadsSplitPane;
HashMap<Long, String> nameCache = new HashMap();
private ThreadOverviewPanel overviewPanel;
private boolean plotterListening = false;
private static final String threadCountKey = "threadCount";
private static final String peakKey = "peak";
private static final Color threadCountColor = Plotter.defaultColor;
private static final Color peakColor = Color.red;
private static final Border thinEmptyBorder = new EmptyBorder(2, 2, 2, 2);
private static final String infoLabelFormat = "ThreadTab.infoLabelFormat";
/*
Hierarchy of panels and layouts for this tab:
ThreadTab (BorderLayout)
North: topPanel (BorderLayout)
Center: controlPanel (FlowLayout)
timeComboBox
Center: plotterPanel (BorderLayout)
Center: plotter
*/
public static String getTabName() {
return Messages.THREADS;
}
public ThreadTab(VMPanel vmPanel) {
super(vmPanel, getTabName());
setLayout(new BorderLayout(0, 0));
setBorder(new EmptyBorder(4, 4, 3, 4));
JPanel topPanel = new JPanel(new BorderLayout());
JPanel plotterPanel = new JPanel(new VariableGridLayout(0, 1, 4, 4, true, true));
add(topPanel, BorderLayout.NORTH);
add(plotterPanel, BorderLayout.CENTER);
JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 5));
topPanel.add(controlPanel, BorderLayout.CENTER);
threadMeter = new PlotterPanel(Messages.NUMBER_OF_THREADS,
Plotter.Unit.NONE, true);
threadMeter.plotter.createSequence(threadCountKey, Messages.LIVE_THREADS, threadCountColor, true);
threadMeter.plotter.createSequence(peakKey, Messages.PEAK, peakColor, true);
setAccessibleName(threadMeter.plotter,
Messages.THREAD_TAB_THREAD_PLOTTER_ACCESSIBLE_NAME);
plotterPanel.add(threadMeter);
timeComboBox = new TimeComboBox(threadMeter.plotter);
controlPanel.add(new LabeledComponent(Messages.TIME_RANGE_COLON,
Resources.getMnemonicInt(Messages.TIME_RANGE_COLON),
timeComboBox));
listModel = new DefaultListModel<Long>();
JTextArea textArea = new JTextArea();
textArea.setBorder(thinEmptyBorder);
textArea.setEditable(false);
setAccessibleName(textArea,
Messages.THREAD_TAB_THREAD_INFO_ACCESSIBLE_NAME);
ThreadJList list = new ThreadJList(listModel, textArea);
Dimension di = new Dimension(super.getPreferredSize());
di.width = Math.min(di.width, 200);
JScrollPane threadlistSP = new JScrollPane(list);
threadlistSP.setPreferredSize(di);
threadlistSP.setBorder(null);
JScrollPane textAreaSP = new JScrollPane(textArea);
textAreaSP.setBorder(null);
threadListTabbedPane = new JTabbedPane(JTabbedPane.TOP);
threadsSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
threadlistSP, textAreaSP);
threadsSplitPane.setOneTouchExpandable(true);
threadsSplitPane.setBorder(null);
JPanel firstTabPanel = new JPanel(new BorderLayout());
firstTabPanel.setOpaque(false);
JPanel firstTabToolPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 2));
firstTabToolPanel.setOpaque(false);
filterTF = new PromptingTextField("Filter", 20);
filterTF.getDocument().addDocumentListener(this);
firstTabToolPanel.add(filterTF);
JSeparator separator = new JSeparator(JSeparator.VERTICAL);
separator.setPreferredSize(new Dimension(separator.getPreferredSize().width,
filterTF.getPreferredSize().height));
firstTabToolPanel.add(separator);
JButton detectDeadlockButton = new JButton(Messages.DETECT_DEADLOCK);
detectDeadlockButton.setMnemonic(Resources.getMnemonicInt(Messages.DETECT_DEADLOCK));
detectDeadlockButton.setActionCommand("detectDeadlock");
detectDeadlockButton.addActionListener(this);
detectDeadlockButton.setToolTipText(Messages.DETECT_DEADLOCK_TOOLTIP);
firstTabToolPanel.add(detectDeadlockButton);
messageLabel = new JLabel();
firstTabToolPanel.add(messageLabel);
firstTabPanel.add(threadsSplitPane, BorderLayout.CENTER);
firstTabPanel.add(firstTabToolPanel, BorderLayout.SOUTH);
threadListTabbedPane.addTab(Messages.THREADS, firstTabPanel);
plotterPanel.add(threadListTabbedPane);
}
private long oldThreads[] = new long[0];
public SwingWorker<?, ?> newSwingWorker() {
final ProxyClient proxyClient = vmPanel.getProxyClient();
if (!plotterListening) {
proxyClient.addWeakPropertyChangeListener(threadMeter.plotter);
plotterListening = true;
}
return new SwingWorker<Boolean, Object>() {
private int tlCount;
private int tpCount;
private long ttCount;
private long[] threads;
private long timeStamp;
public Boolean doInBackground() {
try {
ThreadMXBean threadMBean = proxyClient.getThreadMXBean();
tlCount = threadMBean.getThreadCount();
tpCount = threadMBean.getPeakThreadCount();
if (overviewPanel != null) {
ttCount = threadMBean.getTotalStartedThreadCount();
} else {
ttCount = 0L;
}
threads = threadMBean.getAllThreadIds();
for (long newThread : threads) {
if (nameCache.get(newThread) == null) {
ThreadInfo ti = threadMBean.getThreadInfo(newThread);
if (ti != null) {
String name = ti.getThreadName();
if (name != null) {
nameCache.put(newThread, name);
}
}
}
}
timeStamp = System.currentTimeMillis();
return true;
} catch (IOException e) {
return false;
} catch (UndeclaredThrowableException e) {
return false;
}
}
protected void done() {
try {
if (!get()) {
return;
}
} catch (InterruptedException ex) {
return;
} catch (ExecutionException ex) {
if (JConsole.isDebug()) {
ex.printStackTrace();
}
return;
}
threadMeter.plotter.addValues(timeStamp, tlCount, tpCount);
threadMeter.setValueLabel(tlCount+"");
if (overviewPanel != null) {
overviewPanel.updateThreadsInfo(tlCount, tpCount, ttCount, timeStamp);
}
String filter = filterTF.getText().toLowerCase(Locale.ENGLISH);
boolean doFilter = (filter.length() > 0);
ArrayList<Long> l = new ArrayList();
for (long t : threads) {
l.add(t);
}
Iterator<Long> iterator = l.iterator();
while (iterator.hasNext()) {
long newThread = iterator.next();
String name = nameCache.get(newThread);
if (doFilter && name != null &&
name.toLowerCase(Locale.ENGLISH).indexOf(filter) < 0) {
iterator.remove();
}
}
long[] newThreads = threads;
if (l.size() < threads.length) {
newThreads = new long[l.size()];
for (int i = 0; i < newThreads.length; i++) {
newThreads[i] = l.get(i);
}
}
for (long oldThread : oldThreads) {
boolean found = false;
for (long newThread : newThreads) {
if (newThread == oldThread) {
found = true;
break;
}
}
if (!found) {
listModel.removeElement(oldThread);
if (!doFilter) {
nameCache.remove(oldThread);
}
}
}
// Threads are in reverse chronological order
for (int i = newThreads.length - 1; i >= 0; i--) {
long newThread = newThreads[i];
boolean found = false;
for (long oldThread : oldThreads) {
if (newThread == oldThread) {
found = true;
break;
}
}
if (!found) {
listModel.addElement(newThread);
}
}
oldThreads = newThreads;
}
};
}
long lastSelected = -1;
public void valueChanged(ListSelectionEvent ev) {
ThreadJList list = (ThreadJList)ev.getSource();
final JTextArea textArea = list.textArea;
Long selected = (Long)list.getSelectedValue();
if (selected == null) {
if (lastSelected != -1) {
selected = lastSelected;
}
} else {
lastSelected = selected;
}
textArea.setText("");
if (selected != null) {
final long threadID = selected;
workerAdd(new Runnable() {
public void run() {
ProxyClient proxyClient = vmPanel.getProxyClient();
StringBuilder sb = new StringBuilder();
try {
ThreadMXBean threadMBean = proxyClient.getThreadMXBean();
ThreadInfo ti = null;
MonitorInfo[] monitors = null;
if (proxyClient.isLockUsageSupported() &&
threadMBean.isObjectMonitorUsageSupported()) {
// VMs that support the monitor usage monitoring
ThreadInfo[] infos = threadMBean.dumpAllThreads(true, false);
for (ThreadInfo info : infos) {
if (info.getThreadId() == threadID) {
ti = info;
monitors = info.getLockedMonitors();
break;
}
}
} else {
// VM doesn't support monitor usage monitoring
ti = threadMBean.getThreadInfo(threadID, Integer.MAX_VALUE);
}
if (ti != null) {
if (ti.getLockName() == null) {
sb.append(Resources.format(Messages.NAME_STATE,
ti.getThreadName(),
ti.getThreadState().toString()));
} else if (ti.getLockOwnerName() == null) {
sb.append(Resources.format(Messages.NAME_STATE_LOCK_NAME,
ti.getThreadName(),
ti.getThreadState().toString(),
ti.getLockName()));
} else {
sb.append(Resources.format(Messages.NAME_STATE_LOCK_NAME_LOCK_OWNER,
ti.getThreadName(),
ti.getThreadState().toString(),
ti.getLockName(),
ti.getLockOwnerName()));
}
sb.append(Resources.format(Messages.BLOCKED_COUNT_WAITED_COUNT,
ti.getBlockedCount(),
ti.getWaitedCount()));
sb.append(Messages.STACK_TRACE);
int index = 0;
for (StackTraceElement e : ti.getStackTrace()) {
sb.append(e.toString()+"\n");
if (monitors != null) {
for (MonitorInfo mi : monitors) {
if (mi.getLockedStackDepth() == index) {
sb.append(Resources.format(Messages.MONITOR_LOCKED, mi.toString()));
}
}
}
index++;
}
}
} catch (IOException ex) {
// Ignore
} catch (UndeclaredThrowableException e) {
proxyClient.markAsDead();
}
final String text = sb.toString();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.setText(text);
textArea.setCaretPosition(0);
}
});
}
});
}
}
private void doUpdate() {
workerAdd(new Runnable() {
public void run() {
update();
}
});
}
private void detectDeadlock() {
workerAdd(new Runnable() {
public void run() {
try {
final Long[][] deadlockedThreads = getDeadlockedThreadIds();
if (deadlockedThreads == null || deadlockedThreads.length == 0) {
// Display message for 30 seconds. Do it on a separate thread so
// the sleep won't hold up the worker queue.
// This will be replaced later by separate statusbar logic.
new Thread() {
public void run() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
String msg = Messages.NO_DEADLOCK_DETECTED;
messageLabel.setText(msg);
threadListTabbedPane.revalidate();
}
});
sleep(30 * 1000);
} catch (InterruptedException ex) {
// Ignore
} catch (InvocationTargetException ex) {
// Ignore
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
messageLabel.setText("");
}
});
}
}.start();
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Remove old deadlock tabs
while (threadListTabbedPane.getTabCount() > 1) {
threadListTabbedPane.removeTabAt(1);
}
if (deadlockedThreads != null) {
for (int i = 0; i < deadlockedThreads.length; i++) {
DefaultListModel<Long> listModel = new DefaultListModel();
JTextArea textArea = new JTextArea();
textArea.setBorder(thinEmptyBorder);
textArea.setEditable(false);
setAccessibleName(textArea,
Messages.THREAD_TAB_THREAD_INFO_ACCESSIBLE_NAME);
ThreadJList list = new ThreadJList(listModel, textArea);
JScrollPane threadlistSP = new JScrollPane(list);
JScrollPane textAreaSP = new JScrollPane(textArea);
threadlistSP.setBorder(null);
textAreaSP.setBorder(null);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
threadlistSP, textAreaSP);
splitPane.setOneTouchExpandable(true);
splitPane.setBorder(null);
splitPane.setDividerLocation(threadsSplitPane.getDividerLocation());
String tabName;
if (deadlockedThreads.length > 1) {
tabName = Resources.format(Messages.DEADLOCK_TAB_N, i+1);
} else {
tabName = Messages.DEADLOCK_TAB;
}
threadListTabbedPane.addTab(tabName, splitPane);
for (long t : deadlockedThreads[i]) {
listModel.addElement(t);
}
}
threadListTabbedPane.setSelectedIndex(1);
}
}
});
} catch (IOException e) {
// Ignore
} catch (UndeclaredThrowableException e) {
vmPanel.getProxyClient().markAsDead();
}
}
});
}
// Return deadlocked threads or null
public Long[][] getDeadlockedThreadIds() throws IOException {
ProxyClient proxyClient = vmPanel.getProxyClient();
ThreadMXBean threadMBean = proxyClient.getThreadMXBean();
long[] ids = proxyClient.findDeadlockedThreads();
if (ids == null) {
return null;
}
ThreadInfo[] infos = threadMBean.getThreadInfo(ids, Integer.MAX_VALUE);
List<Long[]> dcycles = new ArrayList();
List<Long> cycle = new ArrayList();
// keep track of which thread is visited
// one thread can only be in one cycle
boolean[] visited = new boolean[ids.length];
int deadlockedThread = -1; // Index into arrays
while (true) {
if (deadlockedThread < 0) {
if (cycle.size() > 0) {
// a cycle found
dcycles.add(cycle.toArray(new Long[0]));
cycle = new ArrayList<Long>();
}
// start a new cycle from a non-visited thread
for (int j = 0; j < ids.length; j++) {
if (!visited[j]) {
deadlockedThread = j;
visited[j] = true;
break;
}
}
if (deadlockedThread < 0) {
// done
break;
}
}
cycle.add(ids[deadlockedThread]);
long nextThreadId = infos[deadlockedThread].getLockOwnerId();
for (int j = 0; j < ids.length; j++) {
ThreadInfo ti = infos[j];
if (ti.getThreadId() == nextThreadId) {
if (visited[j]) {
deadlockedThread = -1;
} else {
deadlockedThread = j;
visited[j] = true;
}
break;
}
}
}
return dcycles.toArray(new Long[0][0]);
}
// ActionListener interface
public void actionPerformed(ActionEvent evt) {
String cmd = ((AbstractButton)evt.getSource()).getActionCommand();
if (cmd == "detectDeadlock") {
messageLabel.setText("");
detectDeadlock();
}
}
// DocumentListener interface
public void insertUpdate(DocumentEvent e) {
doUpdate();
}
public void removeUpdate(DocumentEvent e) {
doUpdate();
}
public void changedUpdate(DocumentEvent e) {
doUpdate();
}
private class ThreadJList extends JList<Long> {
private JTextArea textArea;
ThreadJList(DefaultListModel<Long> listModel, JTextArea textArea) {
super(listModel);
this.textArea = textArea;
setBorder(thinEmptyBorder);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
textArea.setText(Messages.THREAD_TAB_INITIAL_STACK_TRACE_MESSAGE);
addListSelectionListener(ThreadTab.this);
setCellRenderer(new DefaultListCellRenderer() {
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value != null) {
String name = nameCache.get(value);
if (name == null) {
name = value.toString();
}
setText(name);
}
return this;
}
});
}
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
d.width = Math.max(d.width, 100);
return d;
}
}
private class PromptingTextField extends JTextField implements FocusListener {
private String prompt;
boolean promptRemoved = false;
Color fg;
public PromptingTextField(String prompt, int columns) {
super(prompt, columns);
this.prompt = prompt;
updateForeground();
addFocusListener(this);
setAccessibleName(this, prompt);
}
@Override
public void revalidate() {
super.revalidate();
updateForeground();
}
private void updateForeground() {
this.fg = UIManager.getColor("TextField.foreground");
if (promptRemoved) {
setForeground(fg);
} else {
setForeground(Color.gray);
}
}
public String getText() {
if (!promptRemoved) {
return "";
} else {
return super.getText();
}
}
public void focusGained(FocusEvent e) {
if (!promptRemoved) {
setText("");
setForeground(fg);
promptRemoved = true;
}
}
public void focusLost(FocusEvent e) {
if (promptRemoved && getText().equals("")) {
setText(prompt);
setForeground(Color.gray);
promptRemoved = false;
}
}
}
OverviewPanel[] getOverviewPanels() {
if (overviewPanel == null) {
overviewPanel = new ThreadOverviewPanel();
}
return new OverviewPanel[] { overviewPanel };
}
private static class ThreadOverviewPanel extends OverviewPanel {
ThreadOverviewPanel() {
super(Messages.THREADS, threadCountKey, Messages.LIVE_THREADS, null);
}
private void updateThreadsInfo(long tlCount, long tpCount, long ttCount, long timeStamp) {
getPlotter().addValues(timeStamp, tlCount);
getInfoLabel().setText(Resources.format(infoLabelFormat, tlCount, tpCount, ttCount));
}
}
}
Other Java examples (source code examples)
Here is a short list of links related to this Java ThreadTab.java source code file:
|