多线程Demo学习(使用守护线程,休眠线程,线程插队)
一.使用守护线程
在学习本demo之前我们先复习下守护线程的知识:Java中的线程可以分为两类,用户线程和守护线程。 其中用户线程是为了完成任务而存在的,而守护线程是为其他线程服务的,也就是说守护线程存在的意义就是守护其他的非守护线程,只有当所有非守护线程都执行完毕时,守护线程才可以结束。
下面的例子中创建两个线程,一个是用户线程,用来输出一些语句。一个是守护线程,用来计算程序的运行时间。
工作者任务:
public class Worker implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("《Java编程词典》第" + i + "次更新!");// 用户线程用来输出一些语句
}
}
}
守护线程任务:
public class Timer implements Runnable {
public void run() {
long currentTime = System.currentTimeMillis();// 获得系统当前时间
long processTime = 0;// 设置系统运行时间为0
while (true) {// 如果系统运行时间发生变化就输出
if ((System.currentTimeMillis() - currentTime) > processTime) {
processTime = System.currentTimeMillis() - currentTime;
System.out.println("程序运行时间:" + processTime);
}
}
}
}
public class DaemonThreadTest {
public static void main(String[] args) {
Thread userThread = new Thread(new Worker()); // 创建用户线程
Thread daemonThread = new Thread(new Timer()); // 创建守护线程
daemonThread.setDaemon(true); // 设置守护线程
userThread.start(); // 启动用户线程
daemonThread.start(); // 启动守护线程
}
}
运行结果如下:

看到效果了,下面我们对代码进行解析:
首先是工作者任务,很简单就是打印值得次数的语句。
然后是守护者任务:
public class Timer implements Runnable {
public void run() {
long currentTime = System.currentTimeMillis();// 获得系统当前时间
long processTime = 0;// 设置系统运行时间为0
while (true) {// 如果系统运行时间发生变化就输出
if ((System.currentTimeMillis() - currentTime) > processTime) {
processTime = System.currentTimeMillis() - currentTime;
System.out.println("程序运行时间:" + processTime);
}
}
}
}
它的运行逻辑是首先获得系统当前的时间,然后执行死循环,当工作者线程都结束后它会自己结束。
关键API:
| 方法名 | 作用 |
|---|---|
| isDeamon() | 测试一个线程是否为守护线程 |
| setDeamon(boolean on) | 将一个线程标记为守护或用户线程 |
二.休眠当前线程
休眠线程使用的API是:
| 方法名 | 作用 |
|---|---|
| sleep(long millis) | 让线程休眠指定的毫秒数 |
| sleep(long millis,int nanos) | 让线程休眠指定的毫秒数加纳秒数 |
在使用这个API之前,首先我们要知道休眠的含义:当一个线程调用了sleep方法,就意味着这个线程暂停执行进入BLOCKED状态,并在指定时间后进入RUNNABLE状态。
下面我们通过模拟龟兔赛跑的例子来学习线程休眠:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import java.awt.GridLayout;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.UIManager;
import java.awt.Font;
public class RaceFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 4941729012450153307L;
private JPanel contentPane;
private JTextArea rabbitTextArea;
private JTextArea tortoiseTextArea;
/**
* 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 {
RaceFrame frame = new RaceFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public RaceFrame() {
setTitle("\u4F11\u7720\u5F53\u524D\u7EBF\u7A0B");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
JPanel buttonPanel = new JPanel();
contentPane.add(buttonPanel, BorderLayout.SOUTH);
JButton button = new JButton("\u6BD4\u8D5B\u5F00\u59CB");
button.setFont(new Font("微软雅黑", Font.PLAIN, 16));
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
do_button_actionPerformed(arg0);
}
});
buttonPanel.add(button);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.CENTER);
panel.setLayout(new GridLayout(1, 2, 5, 5));
JPanel rabbitPanel = new JPanel();
panel.add(rabbitPanel);
rabbitPanel.setLayout(new BorderLayout(0, 0));
JLabel rabbitLabel = new JLabel("\u5154\u5B50\u7684\u6BD4\u8D5B\u8BB0\u5F55");
rabbitLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16));
rabbitLabel.setHorizontalAlignment(SwingConstants.CENTER);
rabbitPanel.add(rabbitLabel, BorderLayout.NORTH);
JScrollPane rabbitScrollPane = new JScrollPane();
rabbitPanel.add(rabbitScrollPane, BorderLayout.CENTER);
rabbitTextArea = new JTextArea();
rabbitTextArea.setFont(new Font("微软雅黑", Font.PLAIN, 16));
rabbitScrollPane.setViewportView(rabbitTextArea);
JPanel tortoisePanel = new JPanel();
panel.add(tortoisePanel);
tortoisePanel.setLayout(new BorderLayout(0, 0));
JLabel tortoiseLabel = new JLabel("\u4E4C\u9F9F\u7684\u6BD4\u8D5B\u8BB0\u5F55");
tortoiseLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16));
tortoiseLabel.setHorizontalAlignment(SwingConstants.CENTER);
tortoisePanel.add(tortoiseLabel, BorderLayout.NORTH);
JScrollPane tortoiseScrollPane = new JScrollPane();
tortoisePanel.add(tortoiseScrollPane, BorderLayout.CENTER);
tortoiseTextArea = new JTextArea();
tortoiseTextArea.setFont(new Font("微软雅黑", Font.PLAIN, 16));
tortoiseScrollPane.setViewportView(tortoiseTextArea);
}
protected void do_button_actionPerformed(ActionEvent arg0) {
Runnable run1 = new Rabbit();
Runnable run2 = new Tortoise();
Thread rabbit = new Thread(run1);
Thread tortoise = new Thread(run2);
rabbit.start();
tortoise.start();
}
private class Rabbit implements Runnable {
@Override
public void run() {
for (int i = 1; i < 11; i++) {// 循环10次模拟赛跑的过程
String text = rabbitTextArea.getText();// 获得文本域中的信息
try {
Thread.sleep(1);// 线程休眠0.001秒,模拟兔子在跑步
} catch (InterruptedException e) {
e.printStackTrace();
}
rabbitTextArea.setText(text + "兔子跑了" + i + "0米\n");// 显示兔子的跑步距离
if (i == 9) {
rabbitTextArea.setText(text + "兔子在睡觉\n");// 当跑了90米时开始睡觉
try {
Thread.sleep(10000);// 线程休眠10秒,模拟兔子在睡觉
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i == 10) {
try {
Thread.sleep(1);// 线程休眠0.001秒,模拟兔子在跑步
} catch (InterruptedException e) {
e.printStackTrace();
}
rabbitTextArea.setText(text + "兔子到达终点\n");// 显示兔子到达了终点
}
}
}
}
private class Tortoise implements Runnable {
@Override
public void run() {
for (int i = 1; i < 11; i++) {
String text = tortoiseTextArea.getText();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
tortoiseTextArea.setText(text + "乌龟跑了" + i + "0米\n");
if (i == 10) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
tortoiseTextArea.setText(text + "乌龟到达终点\n");
}
}
}
}
}
运行效果:

下面我们对其中的龟兔的赛跑过程进行分析:
1)兔子的跑步过程
private class Rabbit implements Runnable {
@Override
public void run() {
for (int i = 1; i < 11; i++) {
String text = rabbitTextArea.getText();// 获得文本域中的信息
try {
Thread.sleep(10);// 线程休眠0.01秒,模拟兔子在跑步
} catch (InterruptedException e) {
e.printStackTrace();
}
rabbitTextArea.setText(text + "兔子跑了" + i + "0米\n");// 显示兔子的跑步距离
if (i == 9) {
rabbitTextArea.setText(text + "兔子在睡觉\n");// 当跑了90米时开始睡觉
try {
Thread.sleep(10000);// 线程休眠10秒,模拟兔子在睡觉
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i == 10) {
try {
Thread.sleep(1);// 线程休眠0.001秒,模拟兔子在跑步
} catch (InterruptedException e) {
e.printStackTrace();
}
rabbitTextArea.setText(text + "兔子到达终点\n");// 显示兔子到达了终点
}
}
}
}
这里是模拟的是:兔子0.01秒跑10米,当兔子跑到90米时,兔子睡觉,进入休眠状态10秒,在此期间该线程不做任何操作,10秒后,兔子接着跑,到达终点。
反之,乌龟线程没有休息,一直在跑,所以它会先执行完毕。
三.线程的插队运行
我们一般实现线程插队的做法是使用Thread的join()方法:
| 方法名 | 作用 |
|---|---|
| join() | 等待调用该方法的线程终止 |
| join(long millis) | 等待调用该方法的线程终止的时间最长为millis 毫秒 |
| join(long millis,int nanos) | 等待调用该方法的线程终止的时间最长为millil毫秒 加nanos纳秒 |
实例:
public class JoinThread {
public static void main(String[] args) {
Thread thread = new Thread(new EmergencyThread());
thread.start();
for (int i = 1; i < 6; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("正常情况:" + i + "号车出发!");
try {
thread.join();//这条语句让主线程等待thread执行完毕后再执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class EmergencyThread implements Runnable {
@Override
public void run() {
for (int i = 1; i < 6; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("紧急情况:" + i + "号车出发!");
}
}
}
运行效果:


浙公网安备 33010602011771号