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 秒)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值