多线程Demo学习(查看和修改线程名称,查看和修改线程优先级,)
一.查看和修改线程名称
首先先粗略的看一下下面的代码:可以试着运行一下,看一下效果
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ThreadNameTest extends JFrame {
/**
*
*/
private static final long serialVersionUID = -191531973146137575L;
private JPanel contentPane;
private JTable table;
private JTextField textField1;
private JTextField textField2;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");//是Java Swing的一种叫做Nimbus的水晶风格,使用这个语句的目的就是为了让界面更美观。
} catch (Throwable e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ThreadNameTest frame = new ThreadNameTest();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ThreadNameTest() {
addWindowListener(new WindowAdapter() {
@Override
public void windowActivated(WindowEvent e) {
do_this_windowActivated(e);
}
});
setTitle("查看和修改线程名称");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.SOUTH);
textField1 = new JTextField();
textField1.setFont(new Font("微软雅黑", Font.PLAIN, 16));
panel.add(textField1);
textField1.setColumns(6);
JButton button1 = new JButton("新建线程");
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
do_button1_actionPerformed(e);
}
});
button1.setFont(new Font("微软雅黑", Font.PLAIN, 16));
panel.add(button1);
textField2 = new JTextField();
textField2.setFont(new Font("微软雅黑", Font.PLAIN, 16));
panel.add(textField2);
textField2.setColumns(6);
JButton button2 = new JButton("修改名称");
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
do_button2_actionPerformed(e);
}
});
button2.setFont(new Font("微软雅黑", Font.PLAIN, 16));
panel.add(button2);
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
table = new JTable();
table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
table.setRowHeight(30);
JTableHeader header = table.getTableHeader();
header.setFont(new Font("微软雅黑", Font.PLAIN, 16));
header.setPreferredSize(new Dimension(header.getWidth(), 35));
scrollPane.setViewportView(table);
}
//显示当前线程组
protected void do_this_windowActivated(WindowEvent e) {
ThreadGroup group = Thread.currentThread().getThreadGroup();//获得当前线程所在的线程组
Thread[] threads = new Thread[group.activeCount()];//新建线程数组,其大小为当前线程组中活跃的线程的估计数
group.enumerate(threads);//把此线程组中的所有活动线程复制到threads中
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setRowCount(0);
model.setColumnIdentifiers(new Object[] { "线程ID", "线程名称" });
for (Thread thread : threads) {
model.addRow(new Object[] { thread.getId(), thread.getName() });
}
table.setModel(model);
}
//新建线程方法
protected void do_button1_actionPerformed(ActionEvent e) {
Object[] newThread = null;
String name = textField1.getText();//获得新建线程名
if (name.isEmpty()) {
Thread thread = new Thread(new Forever());
thread.start();
newThread = new Object[] { thread.getId(), thread.getName() };
} else {
Thread thread = new Thread(new Forever(), name);
thread.start();
newThread = new Object[] { thread.getId(), name };
}
((DefaultTableModel) table.getModel()).addRow(newThread);//将新建线程信息添加到model中显示
}
//修改线程名称方法
protected void do_button2_actionPerformed(ActionEvent e) {
int selectedRow = table.getSelectedRow();//获得选择行
String newName = textField2.getText();
if ((selectedRow == -1) || newName.isEmpty()) {
return;
}
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setValueAt(newName, selectedRow, 1);
repaint();//重绘
}
private class Forever implements Runnable {
@Override
public void run() {
while (true) {
}
}
}
}
乍一看很神奇对不对,其实并没有那么神奇,当我们学习完下面的代码的过程解析,我们会知道代码多不是问题,问题是我们能找出其核心的地方。
下面我们提取出其中的核心方法:
如何提取呢? 我们可以根据自己看到的运行效果来反向分析,首先,我们可以看到,程序开始运行后,我们在不做任何操作的情况下会显示三个线程,那么代码中一定有一个初始的显示线程的方法,它就是我们要解析的第一个方法,如下:
1)显示当前的线程组中线程的信息
//显示当前线程组
protected void do_this_windowActivated(WindowEvent e) {
ThreadGroup group = Thread.currentThread().getThreadGroup();//获得当前线程所在的线程组
Thread[] threads = new Thread[group.activeCount()];//新建线程数组,其大小为当前线程组中活跃的线程的估计数
group.enumerate(threads);//把此线程组中的所有活动线程复制到threads中
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setRowCount(0);
model.setColumnIdentifiers(new Object[] { "线程ID", "线程名称" });
for (Thread thread : threads) {
model.addRow(new Object[] { thread.getId(), thread.getName() });
}
table.setModel(model);
}
下面我们逐行解释语句来进行学习:首先,这个方法声明并初始化一个局部变量group来存储运行这个方法的线程的线程组,然后有声明并初始化一个threads数组来存储group中的活跃线程,然后复制。 运行到这里,threads中已经存储了线程对象,这些对象的信息就是我们要显示在图形界面中的,下面就是要将这些信息添加到图形界面中,于是就有了下面的操作。
我们可以分析出实现这个功能的关键在于ThreadGroup这个API,不懂的可以看一下多线程Demo学习一。
2)然后分析第二个功能:新建线程,同样我们找到其核心方法:
//新建线程方法
protected void do_button1_actionPerformed(ActionEvent e) {
Object[] newThread = null;
String name = textField1.getText();//获得新建线程名
if (name.isEmpty()) {
Thread thread = new Thread(new Forever());
thread.start();
newThread = new Object[] { thread.getId(), thread.getName() };
} else {
Thread thread = new Thread(new Forever(), name);
thread.start();
newThread = new Object[] { thread.getId(), name };
}
((DefaultTableModel) table.getModel()).addRow(newThread);//将新建线程信息添加到model中显示
}
我们可以看到这里面有一个判断,就是当我们没有在新建线程前面的文本框中填写内容时和填写时的情况的执行方式,这样做可以让我们的程序更完善(在编写任何一个方法的时候,我们要尽可能的想到所有的情况并做出相应的对策),接着就将其添加到图形界面中。
3)最后我们就要分析修改线程名称的方法了:
//修改线程名称方法
protected void do_button2_actionPerformed(ActionEvent e) {
int selectedRow = table.getSelectedRow();//获得选择行
String newName = textField2.getText();
if ((selectedRow == -1) || newName.isEmpty()) {
return;
}
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setValueAt(newName, selectedRow, 1);
repaint();//重绘
}
我们可以看到,这里的修改只是表面修改,它并没有进行线程级别的修改,就是针对这个程序的线程GUI显示修改,在程序的内部线程的名字没变。那么它为什么会这样呢?我猜大概是因为前面的两个方法的线程对象都是局部变量,本方法无法获取,所以也进行不了深层次的修改,如果想要进行深层次的修改(thread.setName()),有如下策略:
1)可以使用全局变量
2)也可以根据线程的id获取线程对象然后进行setName(),代码如下:
//修改线程名称方法
protected void do_button2_actionPerformed(ActionEvent e) {
int selectedRow = table.getSelectedRow();//获得选择行
String newName = textField2.getText();
if ((selectedRow == -1) || newName.isEmpty()) {
return;
}
DefaultTableModel model = (DefaultTableModel) table.getModel();
long threadId= (long)model.getValueAt(selectedRow,0);
Thread thread=findThread(threadId);
thread.setName(newName);
model.setValueAt(thread.getName(), selectedRow, 1);
repaint();//重绘
}
public static Thread findThread(long threadId) {
ThreadGroup group = Thread.currentThread().getThreadGroup();
while(group != null) {
Thread[] threads = new Thread[(int)(group.activeCount() * 1.2)];
int count = group.enumerate(threads, true);
for(int i = 0; i < count; i++) {
if(threadId == threads[i].getId()) {
return threads[i];
}
}
group = group.getParent();
}
return null;
}
二.查看和修改线程优先级
同样我们先看一下代码,看下运行效果:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ThreadPriorityTest extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1127454227002083871L;
private JPanel contentPane;
private JTable table;
private JTextField textField;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Throwable e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ThreadPriorityTest frame = new ThreadPriorityTest();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ThreadPriorityTest() {
addWindowListener(new WindowAdapter() {
@Override
public void windowActivated(WindowEvent e) {
do_this_windowActivated(e);
}
});
setTitle("\u67E5\u770B\u548C\u4FEE\u6539\u7EBF\u7A0B\u4F18\u5148\u7EA7");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.SOUTH);
JLabel label = new JLabel("\u65B0\u4F18\u5148\u7EA7\uFF081~10\uFF09\uFF1A");
label.setFont(new Font("微软雅黑", Font.PLAIN, 16));
panel.add(label);
textField = new JTextField();
textField.setFont(new Font("微软雅黑", Font.PLAIN, 16));
panel.add(textField);
textField.setColumns(10);
JButton button = new JButton("\u4FEE\u6539");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
do_button_actionPerformed(e);
}
});
button.setFont(new Font("微软雅黑", Font.PLAIN, 16));
panel.add(button);
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
table = new JTable();
table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
table.setRowHeight(30);
JTableHeader header = table.getTableHeader();
header.setFont(new Font("微软雅黑", Font.PLAIN, 16));
header.setPreferredSize(new Dimension(header.getWidth(), 35));
scrollPane.setViewportView(table);
}
protected void do_this_windowActivated(WindowEvent e) {
ThreadGroup group = Thread.currentThread().getThreadGroup();// 获得当前线程所在线程组
Thread[] threads = new Thread[group.activeCount()];// 使用数组保存活动状态的线程
group.enumerate(threads);// 获得所有线程
DefaultTableModel model = (DefaultTableModel) table.getModel(); // 获得表格模型
model.setRowCount(0); // 清空表格模型中的数据
model.setColumnIdentifiers(new Object[] { "线程ID", "线程名称", "优先级" }); // 定义表头
for (Thread thread : threads) {// 增加行数据
model.addRow(new Object[] { thread.getId(), thread.getName(), thread.getPriority() });
}
table.setModel(model);// 更新表格模型
}
protected void do_button_actionPerformed(ActionEvent e) {
String text = textField.getText();
Integer priority = Integer.parseInt(text);
int selectedRow = table.getSelectedRow();
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setValueAt(priority, selectedRow, 2);
repaint();
}
}
同样,上面的修改也只是表面修改,我们可以通过第一个例子来对它进行修正。
其中要用的关于线程的新方法:
方法名 | 作用 |
---|---|
getPriority() | 获得线程的优先级 |
setPriority(int newPriority) | 修改线程的优先级 |