Java多线程2

Thread的几个常用属性判断

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否守护线程(后台线程)isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID:是线程的唯一标识,不同线程不会重复
  • 名称:各种调试工具用到
  • 状态:表示线程当前所处的一个情况
  • 优先级:优先级高的线程理论上来说更容易被调度
  • 守护(后台)线程:JVM会在一个进程的所有非后台线程结束后,才会结束运行
  • 是否存活:简单理解为 run() 方法是否运行结束
  • 是否中断

线程ID,名称

  • 每个线程的id一定是不相同的,是动态分配的
  • 线程名称是可以手动指定的,并且线程名称是可能存在重复的情况
public class ThreadDemo1 {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println(t.getName()+"线程ID:"+t.getId());

                System.out.println(t.getName()+"线程名称:"+t.getName());
            }
        };

        Thread threadA = new Thread(runnable,"线程A");
        threadA.start();

        Thread threadB = new Thread(runnable,"线程B");
        threadB.start();

        Thread threadC = new Thread(runnable,"线程C");
        threadC.start();
    }
}

在这里插入图片描述

线程状态

public class ThreadDemoGetState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("线程状态1:"+t.getState());
            }
        });
        System.out.println("线程状态:"+ thread.getState());
        thread.start();

        Thread.sleep(500);
        System.out.println("线程状态2:"+thread.getState());
    }
}

获取线程状态

线程优先级

获取线程优先级

线程创建之后,线程优先级就存在了

优先级是int类型,线程的优先级为1~10,最低的优先级是1,最高的优先级是10,默认的优先级是5。

public class ThreadDemoGetPriority {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("线程优先级1:"+t.getPriority());
            }
        });
        System.out.println("线程优先级2:"+thread.getPriority());
        
        thread.start();
        Thread.sleep(500);//休眠0.5s
        
        System.out.println("线程优先级3:"+thread.getPriority());
    }
}

获取线程优先级

设置线程优先级
setPriority()

public class ThreadDemoSetPriority {
    private final static int MAX_COUNT = 1000;
    public static void main(String[] args) {

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //得到当前线程
                Thread t = Thread.currentThread();
                int priority = t.getPriority();
                for (int i = 0;i<MAX_COUNT;i++){
                    System.out.println(t.getName()+"-优先级:"+priority);
                }
            }
        },"线程A");
        thread1.setPriority(Thread.MAX_PRIORITY);

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                int priority = t.getPriority();
                for (int i = 0; i < MAX_COUNT; i++) {
                    System.out.println(t.getName()+"-优先级:"+priority);
                }
            }
        },"线程B");
        thread2.setPriority(Thread.MIN_PRIORITY);

        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                int priority = t.getPriority();
                for (int i = 0; i < MAX_COUNT; i++) {
                    System.out.println(t.getName()+"-优先级:"+priority);
                }
            }
        },"线程C");
        thread3.setPriority(5);

        thread2.start();
        thread1.start();
        thread3.start();
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意事项:同时启动多个线程,多个线程设置了不同的优先级,并不是优先级最高的就一定先执行完后再执行优先级低的线程,而是高优先级的线程获取到CPU时间片的概率更大,整个的执行大致符合高优先级的线程最先执行完的。

守护线程(后台线程)

线程分类:

  • 用户线程(main默认为用户线程)
  • 守护线程:为用户线程服务的,当一个程序中的所有用户线程都执行结束后,那么守护线程也会随之结束。

thread.isDaemon();//判断是否为守护线程
thread.setDaemon(true);//设置守护线程

当前线程是否为守护线程:true=守护线程,false=用户线程

public class ThreadDemoIsDaemon {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"--是否为守护线程:"+thread.isDaemon());

        Thread t1 = new Thread(()->{
            Thread cThread = Thread.currentThread();
            System.out.println(cThread.getName()+"--是否为守护线程:"+cThread.isDaemon());

            Thread tt1 = new Thread(()->{
                Thread cThread2 = Thread.currentThread();
                System.out.println(cThread2.getName()+"--是否为守护线程:"+cThread2.isDaemon());
            },"子线程的子线程A");

            tt1.start();

        },"子线程A");

        //手动指定线程为守护线程
        t1.setDaemon(true);

        t1.start();

        //主线程休眠1s
        Thread.sleep(1000);
    }
}

在这里插入图片描述
结论

  • main线程(主线程)默认是非守护线程(用户线程)
  • 在用户线程中创建的子线程默认情况下也是用户线程
  • 在守护线程中创建的子线程默认情况下也是守护线程

注意事项:线程的类型(用户or守护)不能在线程运行期间,也就是调用了start() 之后进行设置,如果设置那么JVM会保错

用户线程:

public class userThread {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 10; i++) {
                System.out.println("执行:"+i);
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread.start();
    }
}

在这里插入图片描述
守护线程:

public class daemonThread {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 10; i++) {
                System.out.println("执行:"+i);
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        //将线程设置为守护线程
        thread.setDaemon(true);
        //启动线程
        thread.start();
    }
}

在这里插入图片描述

结论:JVM会等待所有的用户线程全部执行结束后再退出,但是JVM不会等待守护线程执行结束再推出

守护线程 VS 用户线程:
用户线程在Java程序中很重要,JVM一定要等所有的用户线程执行结束后才能自然退出;而守护线程就不一样了,守护线程是为用户线程服务的,所以当所有的用户线程执行结束后,不管守护线程是否执行结束,JVM都会退出执行。

线程存活

public class ThreadDemoByAlive {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            Thread t = Thread.currentThread();
            System.out.println(t.getName()+"--线程是否存活:"+t.isAlive());

            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程执行完了!");
        });
        thread.start();

		//线程如果一直存活,即thread.isAlive()一直为真,将不会执行后面的打印
        while (thread.isAlive()){
        }

        System.out.println("确认线程thread执行完了!");
    }
}

在这里插入图片描述

线程终止

使用自定义标识符来终止线程

public class  ThreadInterrupt1 {
    //声明一个自定义标识符
    private volatile static boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            while (!flag){
                System.out.println("正在转账。。。");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("溜了溜了");
        });
        thread.start();
        Thread.sleep(1000);
        //终止线程
        System.out.println("有内鬼,终止交易");
        flag = true;
    }
}

在这里插入图片描述
使用interrupt()终止线程

public class ThreadInterrupt2 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            System.out.println("终止标志位A:"+Thread.currentThread().isInterrupted());
           while (!Thread.currentThread().isInterrupted()){
               System.out.println("正在转账。。。");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   break;
               }
           }
            System.out.println("???");
            System.out.println("终止标志位B:"+Thread.currentThread().isInterrupted());
        });
        thread.start();

        Thread.sleep(100);
        //终止线程
        thread.interrupt();
        System.out.println("有内鬼,终止交易");
        System.out.println("终止标志位C:"+thread.isInterrupted());
    }
}

在这里插入图片描述
interrupt()需要配合 Thread.interrupted()Thread.currentThread().isInterrupted() 一起使用,从而实现线程的终止

isInterrupted()interrupted()的区别:

  • interrupted()属于静态方法,所有程序都可以直接调用的全局方法;而isInterrupted()属于某个实例的方法
  • interrupted()在使用完之后会重置中断标识符;而isInterrupted()不会重置中断标识符

关于线程的执行顺序

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println(t.getName()+"线程ID:"+t.getId());

                System.out.println(t.getName()+"线程名称:"+t.getName());

                System.out.println(t.getName()+"线程优先级:"+t.getPriority());

            }
        };

        Thread threadA = new Thread(runnable,"线程A");
        threadA.start();

        Thread threadB = new Thread(runnable,"线程B");
        threadB.start();

        Thread threadC = new Thread(runnable,"线程C");
        threadC.start();
    }
}

下面是经过多次运行的结果

在这里插入图片描述
在这里插入图片描述
结论:

  • 每个线程内执行的顺序都是从上到下按顺序执行
  • 多个线程间的执行的顺序是“随机”的

一些其他方法join()、yield()

join()等待某个线程执行结束后,再执行后续的代码

//等待线程thread执行结束后,再执行后续代码
thread.join();

优点:运行时所用的资源更少

yield()让出CPU的执行权

public class ThreadYield {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            //得到当前线程
            Thread cThread = Thread.currentThread();
            for (int i = 0; i < 100; i++) {
                //让出CPU执行权
                Thread.yield();
                System.out.println(cThread.getName());
            }
        },"张三");
        thread.start();

        //创建并启动线程
        new Thread(()->{
            Thread cThread = Thread.currentThread();
            for (int i = 0; i < 100; i++) {
                System.out.println(cThread.getName());
            }
        },"李四").start();
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意事项:yield()方法虽然会出让CPU的执行权,让线程调度器重新调度线程,但还是有一定的机率再一次调用到让出CPU的线程上的,这一次他就会执行让出线程的方法了,因为yield()已经被执行过了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值