• Java多线程详解(二)


    3、线程状态

          线程存在多种状态,包括新状态、可运行状态、运行状态、等待/被阻塞/睡眠/监控/挂起状态和死状态5中状态。

          1)、新状态

          新状态是指线程实例化后,但start方法还没有在该线程上被调用时所处的状态。它还没有达到准备运行的状态,更不是一个执行线程。

          2)、可运行状态

          Start()方法启动后,线程由新状态进入可运行状态。可运行状态就是准备好,可以运行但还没有运行的状态。

          不但stat()方法可以进入运行状态,而且从等待/被阻塞/睡眠/监控/挂起状态也可以进入可运行状态。如调用sleep()方法结束后,调用yield(0方法结束后所作用的线程都进入可运行状态。

          可运行状态也可以说是CPU选择线程的状态。所有的线程不分主次、前后,只要处于可运行状态都有可能被CPU选中运行,当然有可能本线程处于可运行状态,但是很长时间不运行它,这个是一种特殊情况。还有其中情况就是总是运行一个线程,如在一个线程中调用yield()方法后进入可运行状态,但是下面运行的还是这个线程。

          3)、运行状态

    就是当前执行线程所处的状态,它可以转入可运行状态和等待/被阻塞/失眠/监控/挂起状态,但是只能从可运行状态进入运行状态。

          4)、等待/被阻塞/睡眠/监控/挂起状态

          等待/被阻塞/睡眠/监控/挂起状态很复杂,它是很多状态的集合体,但是都起到从运行状态到可运行状态的中介作用。处于运行状态的线程由于某种原因不能继续运行,例如调用sleep()方法、被调用join()方法,此线程就会由运行状态进入等待/被阻塞/睡眠/监控/挂起状态。而当sleep()方法结束后或调用join()方法的线程结束后,该线程就又进入可运行状态。

          进入等待/被阻塞/睡眠/监控/挂起状态的方法除了sleep()、yield()方法和join()方法外,还有suspend()方法,它是指让一个线程把另一个线程挂起。

          5)、死状态

          当线程中的run()方法完成之后,线程就进入了死状态。对处于一个死状态的线程带哦用start()方法会发生异常。

    4、线程的调度

          线程调度程序是JVM中的一部分,它决定在任意指定的时刻应该运行哪个线程,并吧线程带出运行状态。线程的调度定义了java运行环境如何交换任务以及如何选择下一个即将被执行的任务。对线程进行调度又通过优先级、sleep()、yield()、join()方法来完成。在前面说过CPU对线程的选择是不确定的,所以通过调度知识让线程按照某种方式运行,而不能彻底规定它。

          1)、优先级

          用来判定何时允许某个线程运行。理论上优先级高的线程比优先级低的线程可获得更多的CPU时间。实际上获得CPU时间长度与很多因素有关,不能仅靠优先级来判断。设计线程的优先级使用setPriority(int level)方法来设置。在level值中,用MIN_PRIORITY来表示优先级最小1;用MAX_PRIORITY来表示优先级最大10;线程的默认优先级为5即NORM_PRIORITY。

          获得当前线程的优先级的方法是getPriority(),其一般形式为getPriority()。

          看下面应用优先级的程序,它通过执行循环、记录次数来表现出优先级的高低:

    public class test{
        public static void main(String[] str) {
           Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
            MyThread t1 = newMyThread(Thread.NORM_PRIORITY + 2);
            MyThread t2 = newMyThread(Thread.NORM_PRIORITY - 2);
            t1.start();
            t2.start();
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
            t1.stop();
            t2.stop();
            try {
                t1.t.join();
                t2.t.join();
            } catch (Exception e) {
            }
            System.out.println("低优先级线程" +t2.click);
            System.out.println("高优先级线程" +t1.click);
        }
    }
    class MyThread implementsRunnable{
        int click = 0;
        Thread t;
        private volatile boolean running = true;
        public MyThread(int p){
            t = new Thread(this);
            t.setPriority(p);
        }
        @Override
        public void run() {
            while (running) {           
                click++;
            }
        }
        public void stop() {
            running = false;
        }
        public void start() {
            t.start();
        }
    }

          该程序的输出结果与CPU有关,运行本程序还能看出CPU的速度。

          2)、sleep睡眠方法

          线程sleep()是一个静态方法,它强制线程进入睡眠状态。在线程中使用sleep()方法是非常必要的,它起到使线程停顿的作用。Sleep()方法可能抛出InterruptedException异常,在使用sleep()方法时一定要进行异常处理。

    public class test{
        public static void main(String[] str) {
            MyThread1 t1 = new MyThread1();
            MyThread2 t2 = new MyThread2();
            MyThread3 t3 = new MyThread3();
            t1.start();
            t2.start();
            t3.start();
        }
    }
     
    class MyThread1 extendsThread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.print("●");
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    System.err.println("异常:" + e);
                }
            }
        }
    }
     
    class MyThread2 extendsThread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.print("■");
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    System.err.println("异常:" + e);
                }
            }
        }
    }
     
    class MyThread3 extendsThread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.print("▲");
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    System.err.println("异常:" + e);
                }
            }
        }
    }

          我们可以看到运行结果还是不完全确定的,sleep()方法也只是让每个线程都有运行的机会。

          3)、join加入方法

          Join()方法使一个线程1跟在当前运行的线程2的后面运行,当线程1运行完后再继续运行线程2。我们先来看一个例子:

    public class test{
        public static void main(String[] str) {
            MyThread1 t1 = new MyThread1();
            MyThread2 t2 = new MyThread2();
            MyThread3 t3 = new MyThread3();
            t2.mt1 = t1;
            t1.start();
            t2.start();
            t3.start();
        }
    }
     
    class MyThread1 extendsThread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println("●");
                try {
                    Thread.sleep(5000);
                } catch (Exception e) {
                    System.err.println("异常:" + e);
                }
            }
        }
    }
     
    class MyThread2 extendsThread{
        public MyThread1 mt1;
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println("■");
                try {
                    Thread.sleep(5000);
                } catch (Exception e) {
                    System.err.println("异常:" + e);
                }
                if (i == 10) {
                    try {
                        mt1.join();
                    } catch (Exception e) {
                        System.err.println("异常:" + e);
                    }
                }
            }
        }
    }
     
    class MyThread3 extendsThread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println("▲");
                try {
                    Thread.sleep(5000);
                } catch (Exception e) {
                    System.err.println("异常:" + e);
                }
            }
        }
    }

          我们可以看到运行结果为:

          ●▲■●■▲▲●■▲●■▲■●●▲■●■▲●■▲■▲●■●▲▲●■● (i=10) ▲▲●▲●▲●▲●▲●▲●●▲●▲■■■■■■■■■成功构建 (总时间: 29 秒)

          当i = 10后,我们看到只打印出三角和实心圆,即线程t1和t3,当t1运行结束后,我们看到又打印出了正放心,即t2。

          4)、yield让步方法

          yield()方法使当前运行的线程回到可运行状态,状态的问题将在第五小节讲到。Yield()方法的作用是让有相同优先级的线程获得运行机会。yield()方法通常被称为让步方法,但它往往达不到让步的目的,因为它只是让当前线程回到可运行的状态,很可能运行的线程又会是这一个。下面的例子使用默认优先级讲解yield()方法:

    public class test{
        public static void main(String[] str) {
            MyThread1 t1 = new MyThread1();
            MyThread2 t2 = new MyThread2();
            MyThread3 t3 = new MyThread3();
            t1.start();
            t2.start();
            t3.start();
        }
    }
     
    class MyThread1 extendsThread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.print("●");
                Thread.yield();
            }
        }
    }
     
    class MyThread2 extendsThread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.print("■");
                Thread.yield();
            }
        }
    }
     
    class MyThread3 extendsThread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.print("▲");
            }
        }
    }

          我们对t1和t2执行yield()方法,执行结果会先打印出一连串的三角形,即t3。但让步没有完全成功,在三角形中仍然还有正方形和圆形:

          ■●▲▲▲▲▲▲▲●■●▲▲■▲▲▲▲▲▲▲▲▲▲▲●■■●■●■●●■●●■●●●■●■●■●■●■●■●■●■■■■成功构建 (总时间: 0 秒)

     

  • 相关阅读:
    d3.js(v5.7)的比例尺以及坐标轴
    d3.js(v5.7)的node与数据匹配(自动匹配扩展函数)
    d3.js(v5.7)的attr()函数完善(添加obj支持)
    d3.js入门之DOM操作
    d3.js入门学习
    最近在写个人网站,忙碌中。。。
    构建vue项目(vue 2.x)时的一些配置问题(持续更新)
    Python之元组
    Python之列表
    Python之字符串
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3013701.html
Copyright © 2020-2023  润新知