Loading

多线程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 + "号车出发!");
        }
    }
}

运行效果:
在这里插入图片描述

posted @ 2020-12-19 14:08  文牧之  阅读(12)  评论(0)    收藏  举报  来源