线程二:线程的类和常用方法

一,构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名
Thread(ThreadGroup group, Runnable target)线程可以用来被分组管理,分好的组即线程组

举例:Thread(Runnable target, String name)

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(() ->{
            while(true){
               //想要执行的代码
            }
        },"线程名");

        t.start();
    }
}

执行代码,使用 JConsole 工具查看线程,发现线程名就是进程所设置的名字。

当我们没有手动设置线程名时,系统会自动为我们设置一个,默认是按照Thread-0,1,2....

线程名是可以重复的。

           

二,常见属性

属性获取方法
IDgetld()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

1. getld()

获取线程 ID。ID 是 JVM 生成的身份标识,具有唯一性。

2. getName()

获取线程名。一个进程的不同线程的线程名可能是一样的。

3. getState()

获取线程状态。Java中对线程状态又进行进一步的区分,比系统原生状态更丰富。

4. getPriority()

获取线程的优先级,在 Java 中设置优先级,会对内核调度器产生一些影响,但是由于系统的随即调度,所以这个影响并不是很明显。

5. isDaemon()

是否为守护线程,也可以叫后台线程。相应的,也有前台线程。

前台线程的运行会阻止进程结束,但是守护线程(后台线程)不会。

一般我们写入的代码默认为前台线程。

演示代码:

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(() ->{
            while(true){
                System.out.println("t 线程");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
    }
}

运行结果:一直打印 " t 线程 "

上述代码一共有两个线程:main 线程和 t 线程。两个线程均为前台线程,所以当 main 线程执行结束时,t 线程阻止进程结束,还会继续执行。

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(() ->{
            while(true){
                System.out.println("t 线程");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        /*setdaemon必须设置在start之前,
         true为后台,不会阻止进程结束
         非true为前台,会阻止进程结束*/
        t.setDaemon(true);

        t.start();
    }
}

运行结果:

上述代码我们将 t 线程设置为后台进程,所以当 main 线程执行结束时,t 线程不会阻止进程结束,进程就此结束。

6. isAlive()

判断内核中的线程是否还存活。

public class ThreadDemo6 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread( () -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(t.isAlive());
        t.start();
        System.out.println(t.isAlive());
        //时间参数要大于上面的,确保线程执行完毕
        Thread.sleep(2000);
        System.out.println(t.isAlive());
    }
}

运行结果:

原因解释:

        Java 代码中定义的线程对象实例的生命周期和内核中的 PCB 生命周期完全不一样。

        代码运行到 Thread t = new Thread() 时,此时只有一个 t 对象,但是内核 PCB 还没有这个线程,所以此时运行结果为 “false”;当代码运行了 t.start() 之后,才在内核中创建出这个 PCB ,所以此时运行结果为 “true”;最后线程执行完 run() ,内核中的线程也就结束了,PCB 释放,所以此时运行结果为 “false”。

7. isInterrupted()

获取线程的中断标志。

public class Threaddemo7 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread( () -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Thread is running");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //屏蔽是防止控制台显示异常信息
                    //e.printStackTrace();
                    //因为 t.interrupt() 会提前打断sleep的休眠期,导致清除 interrupt 的标志位
                    break;
                }
            }
            System.out.println("Thread is stopped");
        });
        t.start();

        Thread.sleep(3000);
        System.out.println("调用interrupt()前:"+t.isInterrupted());
        System.out.println("线程中断");
        t.interrupt();
        System.out.println("调用interrupt()后:"+t.isInterrupted());
    }
}

运行结果:

三,常用方法

1. start()

作用:线程对象只有调用了 start() 方法才会真正创建一个线程(内核中创建 PBC )。

未调用 start() :

public class Demo1 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("这是 t 线程");
        });

        System.out.println("这是 main 线程");
    }
}

// 运行结果:这是 main 线程

调用 start() :

public class Demo1 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("这是 t 线程");
        });

        t.start();
        System.out.println("这是 main 线程");
    }
}

//运行结果:
//这是 main 线程
//这是 t 线程

调用两次 start() :

public class Demo1 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("这是 t 线程");
        });

        t.start();
        t.start();
    }
}

运行结果:

代码报错:非法的线程状态。

总结:

1). 线程对象只有调用了 start() 方法后才会创建出真正的线程。

2). 一个线程对象只能调用一次 start() 方法。

2. interrupt()

作用:interrupt() 中断线程,中断线程操作实质上是修改了一下中断标示位为 true ,核心是让 run() 方法执行结束(具体实践由代码决定)。

引入标志位中断代码:

public class Demo1 {
    //引入一个标志位
    private static boolean isQuit = true;

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            //当 isQuit 为 flase 时,while 循环结束
            while (isQuit) {
                System.out.println("Thread is running");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Thread is over");
        });

        t.start();

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

        System.out.println("让 t 线程结束");
        isQuit = false;
    }
}

运行结果:

  
   注意:main 线程想要让 t 线程结束的前提是代码逻辑对此有所支持,并不是任何代码都可以实现的。

但是有时候再去自定义一个标志位有一点麻烦,此时我们就可以用 interrupt() 方法,使用 Thread 实例内部自带的标志位代替自定义的标志位。

如何使用一个 interrupt() 方法实现:

public class Threaddemo7 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread( () -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Thread is running");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //屏蔽是防止控制台显示异常信息
                    //e.printStackTrace();
                    //因为 t.interrupt() 会提前打断sleep的休眠期,导致清除 interrupt 的标志位
                    break;
                }
            }
            System.out.println("Thread is stopped");
        });
        t.start();

        Thread.sleep(3000);
        System.out.println("线程中断");
        t.interrupt();
    }
}

运行结果:

3. join()

作用:影响线程的先后顺序(固定条件的等待),比如现在有 t1 和 t2 两个线程,如果 t2 线程调用 t1.join 方法,则必学先让 t1 线程执行完毕,才能执行 t2 线程, join() 是可能阻塞 t2 线程,让其暂时不参与 CPU 调度。确定的不是执行顺序,而是结束顺序。

4. sleep()

令当前线程至少休眠 n 毫秒(固定时间的等待,防止无休止的休眠),其中 1000ms = 1s

5. currentThread()

获取当前线程状态。

重点:start() 和 run() 的区别:

线程中 start() 和 run() 的区别-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值