Java多线程之线程状态案例

时间:2021-12-10 18:17:59

sleep阻塞

Thread.sleep(times)使当前线程从Running状态放弃处理器进入Block状态,休眠times毫秒,再返回Runnable状态。

new Thread(new Runnable() {

    @Override
    public void run() {
        SimpleDateFormat format=new SimpleDateFormat("hh:mm:ss");
        //输出系统时间的时分秒。每隔一秒显示一次。可能会出现跳秒的情况,因为阻塞1秒过后进入runnable状态,等待分配时间片进入running状态后还需要一点时间
        while(true){
            try {
                Thread.sleep(1000);

            } catch (InterruptedException e) {
                 e.printStackTrace();

            }
             System.out.println(format.format(new Date()));
          }
    }

}).start();




当一个线程处于睡眠阻塞时,若被其他线程调用.interrupt方法中断,则sleep方法会抛出InterruptedException异常

public static void main(String[] args) {
        /*
         * 表演者:处于睡眠阻塞的线程。
         * 当一个方法中的局部内部类中需要引用该方法的其他局部变量,那么这个变量必须是final的
         */
        final Thread lin = new Thread() {
            public void run() {
                System.out.println("林:刚美完容,睡觉吧!");
                try{
                    // 当一个线程处于睡眠阻塞时,若被其他线程调用interrupt()方法中断,则sleep()方法会抛出 InterruptedException异常
                    Thread.sleep(100000000);
                }
                catch(InterruptedException e){
                    System.out.println("林:干嘛呢!都破了相了!");
                }
            }
        };
        /*
         * 表演者:中断睡眠阻塞的线程
         */
        Thread huang = new Thread() {
            public void run() {
                System.out.println("黄:开始砸墙!");
                for(int i = 0; i < 5; i++){
                    System.out.println("黄:80!");
                    try{
                        Thread.sleep(1000);
                    }
                    catch(InterruptedException e){
                    }
                }
                System.out.println("咣当!");
                System.out.println("黄:搞定!");

                // 中断lin的睡眠阻塞
                lin.interrupt();
            }
        };
        lin.start();
        huang.start();
}



后台线程

后台线程的特点:用法与前台线程无异,只是当一个进程中所有前台线程都结束后,无论后台线程是否还处于运行中都将被强制结束,从而使得进程结束程序退出。

后台线程也称为:守护线程。精灵线程。

在运行程序时,操作系统会启动一个进程来运行jvm,jvm运行后会创建第一个前台线程来运行我们程序的main方法。同时也会创建一个后台线程运行GC。

public static void main(String[] args) {

        // Rose,表演者:前台线程
        Thread rose = new Thread() {
            public void run() {
                for(int i = 0; i < 10; i++){
                    System.out.println("rose:let me go!");
                    try{
                        Thread.sleep(1000);
                    }
                    catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
                System.out.println("rose:啊啊啊啊AAAAAAaaaaaa....");
                System.out.println("噗通!");
            }
        };

        // jack,表演者:后台线程
        Thread jack = new Thread() {
            public void run() {
                while(true){
                    System.out.println("jack:you jump!i jump!");
                    try{
                        Thread.sleep(1000);
                    }
                    catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        };

        /*
         * 设置为后台线程
         * 设置后台线程的方法要在该线程被调用start()方法之前调用
         */
        jack.setDaemon(true);
        rose.start();
        jack.start();
}


线程的优先级

优先级被划分为1-10,1最低10最高。优先级越高的线程被分配时间片的机会越多,那么被CPU执行的机会就越多。

public static void main(String[] args) {
        // 最高优先级的线程
        Thread max = new Thread() {
            public void run() {
                for(int i = 0; i < 1000; i++){
                    System.out.println("max");
                }
            }
        };
        // 最低优先级的线程
        Thread min = new Thread() {
            public void run() {
                for(int i = 0; i < 1000; i++){
                    System.out.println("min");
                }
            }
        };
        // 默认优先级的线程
        Thread norm = new Thread() {
            public void run() {
                for(int i = 0; i < 1000; i++){
                    System.out.println("norm");
                }
            }
        };
        // void setPriority(int p),设置当前线程的优先级, 最高,最低,默认都有常量对应。
        // 设置了优先级也不能100%控制线程调度。只是最大程度的告知线程调度以更多的几率分配时间片给线程优先级高的线程
        max.setPriority(Thread.MAX_PRIORITY);
        min.setPriority(Thread.MIN_PRIORITY);
        // 这项设置可以省略,默认情况下就是该值
        norm.setPriority(Thread.NORM_PRIORITY);

        min.start();
        norm.start();
        max.start();
}


join方法

/**
 * 线程的协同工作 join方法
 */
public class Demo {

    // 判断照片是否下载完成
    public static boolean isFinish = false;

    public static void main(String[] args) {
        // 下载图片的线程
        final Thread download = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("download:开始下载图片");
                for(int i = 0; i <= 100; i++){
                    System.out.println("download:已完成" + i + "%");
                    try{
                        Thread.sleep(50);
                    }
                    catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
                System.out.println("download:图片下载完毕");
                isFinish = true;
            }
        });
        download.start();

        // 用于显示图片的线程
        Thread showImg = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("show:准备显示图片");
                // 等待下载线程工作结束后,再执行下面的代码,
                try{
                    // 此时显示图片的线程就进入阻塞状态,等待download线程运行结束,才能执行下面的代码。注意千万不要在永远也死不了的线程上等待
                    download.join();
                }
                catch(InterruptedException e){
                    e.printStackTrace();
                }
                if(!isFinish){
                    throw new RuntimeException("show:图片还没有下载完");
                }
                System.out.println("show:图片显示完成!");
            }
        });
        showImg.start();
    }

}

wait()、notify()方法

/**
 * 使用wait()与notify()方法完成线程协同工作
 */
public class Demo {

    public static boolean isFinish = false;
    public static Object object = new Object();

    public static void main(String[] args) {

        // 下载图片的线程
        final Thread download = new Thread() {
            public void run() {
                System.out.println("download:开始下载图片");
                for(int i = 0; i <= 100; i++){
                    System.out.println("download:已完成" + i + "%");
                    try{
                        Thread.sleep(50);
                    }
                    catch(InterruptedException e){
                    }
                }
                System.out.println("download:图片下载完毕");
                isFinish = true;// 表示图片下载完毕了

                // 当图片下载完毕后,就可以通知showImg开始显示图片了
                synchronized(object){
                    // 通知在object身上等待的线程解除等待阻塞
                    object.notify();
                }

                System.out.println("download:开始下载附件");
                for(int i = 0; i <= 100; i++){
                    System.out.println("download:已完成" + i + "%");
                    try{
                        Thread.sleep(50);
                    }
                    catch(InterruptedException e){
                    }
                }
                System.out.println("download:附件下载完毕");
            }

        };

        // 用于显示图片的线程
        Thread showImg = new Thread() {
            public void run() {
                System.out.println("show:准备显示图片");
                // 等待下载线程将图片下载结束后,再执行下面的代码
                try{
                    // wait()阻塞会在以下两种情况被解除,1:当download线程结束. 2:当调用了download的notify()
                    synchronized(object){
                        object.wait();
                    }
                }
                catch(InterruptedException e){
                    e.printStackTrace();
                }
                if(!isFinish){
                    throw new RuntimeException("图片没有下载完毕");
                }
                System.out.println("show:图片已经显示了!");
            }
        };

        download.start();
        showImg.start();
    }
}