多线程【二】:Thread类

Thread类

一、有关线程名的一些方法

调用**Thread.currentThread().getName()**可以查看当前线程的名字。

1.Thread.currentThread().getName()方法

在这里插入图片描述未做设置时,主线程叫做main,其他线程是Thread-x。
代码示例:

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Test{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread t1 = new Thread(myThread);
        Thread t2 = new Thread(myThread);
        Thread t3 = new Thread(myThread);
        t1.start();
        t2.start();
        t3.start();
        System.out.println(Thread.currentThread().getName());
    }
}

打印结果:
main
Thread-0
Thread-1
Thread-2

2.public Thread(Runnable target,String name)构造方法

给线程起名字用public Thread(Runnable target,String name)构造方法在这里插入图片描述
代码示例:

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Test{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread t1 = new Thread(myThread,"zy");
        Thread t2 = new Thread(myThread,"zyy");
        Thread t3 = new Thread(myThread,"zyyy");
        t1.start();
        t2.start();
        t3.start();
        System.out.println(Thread.currentThread().getName());
    }
}

打印结果:
main
zyy
zyyy
zy

此处打印结果表明:
代码的运行结果与代码执行顺序或调用顺序是无关的

3.setName()

在这里插入图片描述
调用setName()方法时,要先调用checkAccess()方法,查看是否有修改此线程的权限,如果有,则继续调用setName(),没有权限则出现SecurityException异常。
在这里插入图片描述
代码示例:

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Test{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread t1 = new Thread(myThread,"zy");
        Thread t2 = new Thread(myThread,"zyy");
        Thread t3 = new Thread(myThread,"zyyy");
        t1.start();
        t2.start();
        t3.start();
        t1.setName("z");
        t2.setName("y");
        System.out.println(Thread.currentThread().getName());
    }
}

打印结果:
main
z
y
zyyy

二、守护线程

守护线程是指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。
创建守护线程时,方法和普通线程一样,只是在调用start()方法前,调用setDaemon(true)把该线程标记为守护线程。
在这里插入图片描述
注意:

  1. 在线程启动前设置为守护线程,⽅法是setDaemon(boolean on)。
  2. 使⽤守护线程不要访问共享资源(数据库、⽂件等),例如打开文件等,因为虚拟机退出时,守护线程没有任何机会来关闭文件,这会导致数据丢失。
  3. 守护线程中产⽣的新线程也是守护线程。

代码示例:

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Test{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread t1 = new Thread(myThread,"zy");
        Thread t2 = new Thread(myThread,"zyy");
        t2.setDaemon(true);
        t1.start();
        t2.start();
        System.out.println(Thread.currentThread().getName());
    }
}

打印结果:
main
zy

上⾯的代码运⾏多次可以出现(电脑性能⾜够好的同学可能测试不出来):线程1和主线程执⾏完了,我们的守护线程2就不执⾏了。

三、线程的优先级

设定优先级的方法是:Thread.setPriority(int n) // 1~10, 默认值5。
优先级高的线程被操作系统调度的优先级较高,操作系统对高优先级线程可能调度更频繁,但我们决不能通过设置优先级来确保高优先级的线程一定会先执行。

四、线程的生命周期

在这里插入图片描述

1.sleep()方法

在这里插入图片描述
在这里插入图片描述
调⽤sleep⽅法会进⼊计时等待状态,等时间到了,进⼊的是就绪状态⽽并⾮是运⾏状态。
代码示例:

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Test{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread t1 = new Thread(myThread,"zy");
        Thread t2 = new Thread(myThread,"zyy");
        t1.start();
        try {
            t1.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
        System.out.println(Thread.currentThread().getName());
    }
}

打印结果:
zy
main
zyy
//t1执行后暂停2秒后继续执行其他线程。

2.线程的让步:yield()⽅法

在这里插入图片描述
调⽤yield⽅法会先让别的线程执⾏,但是不确保真正让出。
代码示例:

public class ThreadYield {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }).start();
        while (Thread.activeCount() > 1){  //Thread.activeCount()获取当前所在线程组的活跃线程数
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName());
    }
}

程序未能终止,一致处于等待状态,只打印出Thread-0。

3.线程的等待:join()方法

在这里插入图片描述
代码示例一:

public class Test{
    public static void main(String[] args) throws InterruptedException{
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        thread.start();
        thread.join();
        System.out.println(Thread.currentThread().getName());
    }
}

打印结果:
Thread-0
main

thread.join();等待thread线程执行完毕,故现打印Thread-0

代码示例二:

public class Test{
    public static void main(String[] args) throws InterruptedException{
        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        t.join(2000);
        System.out.println(Thread.currentThread().getName());
    }
}

打印结果:
main
Thread-0

t线程执行之间为2秒,Thread.sleep(5000)为5秒,5秒>2秒,故时间一过2秒,就往下执行,故先打印main线程。

4.线程的中断

1.interrupt()方法

在这里插入图片描述
注意:interrupt不会真正停止⼀个线程,它仅仅是设置了⼀个中断标志,给这个线程发了⼀个信号告诉它,它应该要结束了。

2.静态方法interrupted()

会清除中断标志位
在这里插入图片描述

3.实例⽅法isInterrupted()

不会清除中断标志位
在这里插入图片描述
对目标线程调用interrupt()方法可以请求中断一个线程,目标线程通过检测isInterrupted()标志获取自身是否已中断。如果目标线程处于等待状态,该线程会捕获到InterruptedException。
目标线程检测到isInterrupted()为true或者捕获了InterruptedException都应该立刻结束自身线程。

public class Test{
    public static void test() throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0;i<5;i++){
                    System.out.println(i+"="+Thread.currentThread().isInterrupted());
                }
                //线程运行状态时,需要自行判断线程中断标志位,处理中断操作
                //阻塞状态时,通过捕获及处理异常,来中断线程的中断逻辑
                while (!Thread.interrupted()){
                    System.out.println(Thread.currentThread().getName());
                }
            }
        });
        t.start();//t线程的中断标志位=false
        t.interrupt();//t线程的中断标志位=true
    }
    public static void main(String[] args) throws InterruptedException {
        test();
    }
}

打印结果:
0=true
1=true
2=true
3=true
4=true

因为t线程的中断标志位变为true。

public class Test{
    public static void test() throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().isInterrupted());
                    //线程调用wait()/join()/sleep()阻塞时,如果把当前线程给中断,会直接抛一个异常
                    //抛出异常以后,线程中断标志位会重置
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println(Thread.currentThread().isInterrupted());
                }
            }
        });
        t.start();//t线程的中断标志位=false
        t.interrupt();//t线程的中断标志位=true
    }
    public static void main(String[] args) throws InterruptedException {
        test();
    }
}

打印结果:
true
false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at lesson3.InterruptThread$3.run(InterruptThread.java:50)
at java.lang.Thread.run(Thread.java:748)

public class Test{
    public static volatile boolean IS_INTERRUPTED;
    //使用自定义的中断标志位
    public static void test(){
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                //自定义的标志位能满足线程处于运行态的中断操作
                while (IS_INTERRUPTED){
                    System.out.println(Thread.currentThread().getName());
                }
                //自定义的标志位满足不了线程处于阻塞状态时的中断操作
                try {
                    Thread.sleep(999999);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        IS_INTERRUPTED = true;
    }
    public static void main(String[] args) throws InterruptedException {
        test();
    }
}

无限循环打印Thread-0。原因见注释。

完整的线程生命周期图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值