线程常用构造方法及常用属性

一、线程常见构造方法

在这里插入图片描述

1.Thread()

public static void main(String[] args) {
        //创建线程并初始化
        Thread thread = new Thread(){
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("线程名称:" + t.getName());
            }
        };
        thread.start();
    }

在这里插入图片描述
没有参数,直接创建线程对象,线程名称会以"Thread-"作为前缀加一个数字出现

2.Thread(Runnable target)

public static void main(String[] args) {
        //匿名内部类
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                //业务代码
                Thread thread = Thread.currentThread();
                System.out.println("线程名称:" + thread.getName());
            }
        });
        //启动线程
        thread.start();
    }

在这里插入图片描述

3.Thread(String name)

public static void main(String[] args) {
        //创建线程并初始化
        Thread thread = new Thread("线程1"){
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("线程名称:" + t.getName());
            }
        };
        thread.start();
    }![在这里插入图片描述](https://img-blog.csdnimg.cn/d79ba1131cab4e77bc9cb2f1e70b07de.png)

在这里插入图片描述

4.Thread(Runnable target, String name)

public class ThreadDemo4 {
    public static void main(String[] args) {
        //创建Runnable
        MyThread2 myThread2 =new MyThread2();
        //创建一个线程
        Thread thread = new Thread(myThread2,"线程1");
        thread.start();
    }
}

class MyThread2 implements Runnable{
    @Override
    public void run() {
        //具体业务代码
        Thread thread = Thread.currentThread();//得到当前线程
        System.out.println("线程名称:" + thread.getName());
    }
}

在这里插入图片描述

5.Thread(ThreadGroup group, Runnable target)

线程分组,传入参数线程分组和Runnable对象

代码实现背景:模拟女子100米比赛,将三个运动员分为一组,即一个项目为一组,三个人都是从起点跑到终点,创建线程,传入分组情况及任务;启动线程即三个人开始起跑,等待三个人到达重点再宣布成绩。

import java.util.Random;

public class ThreadDemo12 {
    public static void main(String[] args) {
        //1.创建一个分组(女子100米比赛)
        ThreadGroup group = new ThreadGroup("thread-group");

        //2.定义一个公共的任务(线程的任务)
        Runnable runTask = new Runnable() {
            @Override
            public void run() {//任务
                //生成一个1-3秒的随机数
                int num = (1 + new Random().nextInt(3));
                try {
                    //跑了n秒之后达到了终点
                    Thread.sleep(num*1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("选手到达重点:" + num + "s");
            }
        };

        //3.线程(运动员)
        Thread t1 = new Thread(group,runTask);//选手1

        Thread t2 = new Thread(group,runTask);//选手2

        Thread t3 = new Thread(group,runTask);//选手3

        //运动员1开跑
        t1.start();
        //运动员2开跑
        t2.start();
        //运动员3开跑
        t3.start();

        //所有选手全部到达终点之后宣布成绩
        while (group.activeCount() > 0){
        }
        System.out.println("宣布比赛成绩");
    }
}

在这里插入图片描述

二、线程常用属性

在这里插入图片描述

1.ID( getId() )

 public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                //得到(执行当前任务的)当前线程
                Thread t = Thread.currentThread();
                //打印线程id
                System.out.println("线程ID:" + t.getId());

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

        Thread thread = new Thread(runnable,"线程1");
        thread.start();

        Thread.sleep(500);
        System.out.println();

        Thread thread2 = new Thread(runnable,"线程2");
        thread2.start();

    }

在这里插入图片描述
可以看到每个线程ID是不同,动态分配的

2.名称( getName() )

public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                //得到(执行当前任务的)当前线程
                Thread t = Thread.currentThread();
                //打印线程id
                System.out.println("线程ID:" + t.getId());

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

        Thread thread = new Thread(runnable,"线程1");
        thread.start();

        Thread.sleep(500);
        System.out.println();

        Thread thread2 = new Thread(runnable,"线程1");
        thread2.start();

    }

在这里插入图片描述
将两个线程的名称都改为线程1,可以发现是能正常输出的;
说明线程名称是可以重复的,而线程ID是不可以重复的

3.线程状态( getState() )

线程在没有启动前是新建状态NEW,在启动之后是就绪态RUNNABLE,线程任务执行完之后是终止状态TERMINATED。

 public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                //拿到当前线程
                Thread thread=Thread.currentThread();
                System.out.println("线程状态2:"+thread.getState());
            }
        });
        System.out.println("线程状态1:"+t.getState());
        t.start();
 
        //再次打印线程状态
        Thread.sleep(500);
        System.out.println("线程状态3:"+t.getState());
    }

在这里插入图片描述

4.优先级( getPriority() )

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("线程优先级:" + t.getPriority());
            }
        });
        System.out.println("线程优先级2:" + thread.getPriority());
        thread.start();
        Thread.sleep(500);
        System.out.println("线程优先级3:" + thread.getPriority());
    }

在这里插入图片描述

可以看到线程的优先级从创建开始就存在且默认值为5,优先级最低为1,最大为10

在这里插入图片描述
优先级高的线程理论上说更容易被调度到。但是同时开启多个线程,多个线程设置了不同的优先级,并不是等优先级高的全部执行完再执行优先级低的,而是优先级高的线程获取到cpu的时间片概率更大,也就是更容易被调度到。

5.是否守护线程( isDaemon() )

5.1线程分类
用户线程
守护线程(后台线程)

5.2守护线程作用
守护线程是为⽤户线程服务的,⽤户线程全部结束之后,守护线程会跟随结束。

5.3守护线程的使用
5.3.1 thread.isDaemon()——获取当前线程是否为守护线程:
true=守护线程
false=用户线程

public static void main(String[] args) throws InterruptedException {
        //得到当前线程
        Thread thread=Thread.currentThread();
        System.out.println(thread.getName()+"是否是守护线程"+thread.isDaemon());
 
        Thread thread1=new Thread(()->{
            //得到当前线程
            Thread thread2=Thread.currentThread();
            System.out.println(thread2.getName()+"--是否是守护线程:"+thread2.isDaemon());
 
        },"子线程1");
 
        thread1.start();
 
    }

结论:
1.main线程(主线程)默认是用户线程(非守护线程)
2.在用户线程中创建的子线程也是用户线程

5.3.2 thread.setDaemon(true)——设置守护线程

public static void main(String[] args) throws InterruptedException {
        //得到当前线程(main 主线程)
        Thread thread = Thread.currentThread();
        //main线程为用户线程
        System.out.println("是否为守护线程:" + thread.isDaemon());

        //在main线程(用户线程)中创建的子线程也会是用户线程(默认情况下)
        Thread t1 = new Thread(() -> {
            //得到当前线程t1
            Thread cThread = Thread.currentThread();
            System.out.println(cThread.getName() + "--是否为守护线程:" + cThread.isDaemon());

            //得到当前线程tt1
            Thread tt1 = new Thread(() -> {
                //得到当前线程
                Thread cThread2 = Thread.currentThread();
                System.out.println(cThread2.getName() + "--是否为守护线程" + cThread2.isDaemon());
            },"子线程的子线程1");
            tt1.start();

        },"子线程1");

        //手动指定线程为守护线程
        t1.setDaemon(true);//线程类型的设置不能在start之后进行

        t1.start();

        Thread.sleep(1000);
    }

在这里插入图片描述
可以看到,在设置了子线程为守护线程之后,这个子线程的子线程也是守护线程。

5.3.3 守护线程 VS 用户线程
他们的区别在于:JVM会在一个进程的所有用户线程执行结束后,结束运行;但是不会等所有守护线程结束后再结束运行。

因为守护线程是为用户线程服务的,当用户线程结束后,守护线程也就没有存在的必要了,JVM中的垃圾回收器就是典型的守护线程,当用户线程执行完任务时他也会跟着结束。

6.是否存活( isAlive() )

public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            //得到线程
            Thread thread=Thread.currentThread();
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程执行完了");
        });
        t.start();
 
        while (t.isAlive()){
        }
 
        System.out.println("线程确定执行完了");
    }

当还有线程存活时,while循环就会一直进行,知道线程的任务执行完毕,while才会结束循环。

7. 线程终止

⽬前常⻅的有以下两种⽅式:
1.通过⾃定义标记符来进⾏中断。
2. 调⽤ interrupt() ⽅法来中断。

7.1自定义标识符

public class ThreadInterrupt {
    //声明一个自定义标识符
    private static volatile boolean flag = false;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!flag){
                System.out.println("正在转帐....");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("啊!差点误了大事");
        });

        thread.start();
        Thread.sleep(3000);
        //终止线程
        flag = true;
        System.out.println("有内鬼,终止交易");


    }
}

在这里插入图片描述
7.2使⽤Interrupt()
使⽤ Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替⾃定义标志位.
Thread 内部包含了⼀个 boolean 类型的变量作为线程是否被中断的标记.
在这里插入图片描述

public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            System.out.println("终止标志位:"+Thread.currentThread().isInterrupted());
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("正在转账...");
            }
            System.out.println("险些误了大事!");
            System.out.println("终止标志位2:"+Thread.currentThread().isInterrupted());
            System.out.println("终止标志位2:"+Thread.currentThread().isInterrupted());
            System.out.println("终止标志位2:"+Thread.currentThread().isInterrupted());
            System.out.println("终止标志位2:"+Thread.currentThread().isInterrupted());
            System.out.println();
            System.out.println("终止标志位4:"+Thread.interrupted());
            System.out.println("终止标志位4:"+Thread.interrupted());
            System.out.println("终止标志位4:"+Thread.interrupted());
            System.out.println("终止标志位4:"+Thread.interrupted());
 
        });
        t.start();
        Thread.sleep(100);
        //终止线程
        t.interrupt();
        System.out.println("有内鬼终止交易");
        System.out.println("终止标志位3:"+t.isInterrupted());
 
    }

在这里插入图片描述
在这里插入图片描述
isInterrupted()和interrupted()区别:
1.interrupted()属于静态方法,所有程序都可以直接使用的全局方法;而isInterrupted()属于某个实例的方法。
2.interrupted()在使用完之后会重置中断标志符,而 isInterrupted()不会重置中断标志符。

8.线程等待 join

等待⼀个线程完成它的⼯作后,再进⾏⾃⼰的下⼀步⼯作
在这里插入图片描述
8.1 join不设置时间

public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("1.张三开始上班");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("3.张三下班");
        });
        t1.start();

        //等待t1执行完
        t1.join();

        Thread t2 = new Thread(() -> {
            System.out.println("1.李四开始上班");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("3.李四下班");
        });
        t2.start();

    }

在这里插入图片描述
此处,李四需要等待张三上班结束,再去上班。
8.2 join设置时间
当join设置等待时间过短,那李四就不会等待张三上班结束再上班

public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("1.张三开始上班:"+ LocalDateTime.now());

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("3.张三下班:"+ LocalDateTime.now());
        });
        t1.start();

        //等待t1执行完
        t1.join(500);

        Thread t2 = new Thread(() -> {
            System.out.println("1.李四开始上班:"+ LocalDateTime.now());

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("3.李四下班:"+ LocalDateTime.now());
        });
        t2.start();

    }

在这里插入图片描述

9.yield 让出执行权

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

        Thread t2 = new Thread(() -> {
            Thread cThread = Thread.currentThread();
            for (int i = 0; i < 100; i++) {
                System.out.println("执行线程:" + cThread.getName());
            }
        },"李四");
        t2.start();
    }

yield 不改变线程的状态, 但是会重新去排队,⽽排队之后选择谁是不确定的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值