Java多线程​(二)Thread类常见成员方法

一、多线程三种实现方式的对比

运行结果

优点

缺点

继承Thread类

无法获取

编程比较简单,可以直接使用

扩展性较差,不能再继承其他的类

实现Runnable接口

扩展性强,实现该接口的同时还可以继承其他的类

编程相对复杂,不能直接使用Thread类中的方法

实现Callable接口

可以获取

二、Thread类常见成员方法

方法名称

说明

String getName()

返回此线程的名称

void setName(String name)

设置线程的名字(构造方法也可以设置名字)

static Thread currentThread()

获取当前线程的对象

static void sleep(long time)

让线程休眠指定的时间,单位为毫秒

setPriority(int newPriority)

设置线程的优先级

final int getpriority()

获取线程的优先级

final void setDaemon(boolean on)

设置为守护线程

public static void yield()

出让线程/礼让线程

public static void join()

插入线程/插队线程

(一)getName()和setName()

可以通过setName方法手动给线程命名,否则线程将使用默认名称,格式为Thread-X,其中X为线程的序号,从0开始编号。另外,也可以通过Thread类的构造方法public Thread(String name)给线程命名。

(一)static currentThread()

获取当前线程对象。当JVM虚拟机启动之后,会自动的启动多条线程,其中有一条线程就叫做main线程。他的作用就是去调用main方法,并执行里面的代码。在以前,我们写的所有的代码,其实都是运行在main线程当中。

注意这是一个静态方法,通过类名调用,并不是通过Thread对象调用。因此返回的Thread对象是当前运行的线程的对象。

(二)static sleep()休眠

使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,但受系统计时器和调度器的精度和准确性的限制。该线程不会失去任何监视器的所有权。

注意这是一个静态方法,直接通过Thread调用,表示将当前的线程睡眠一定的时间。

线程类实现代码:

public class MyThread extends Thread{
    public MyThread(String name){
        super(name);
    }

    public MyThread(){
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                // 休眠1秒钟
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 要执行的代码
            System.out.println(getName() + (i + 1));
        }
    }
}

线程使用:

public class ThreadDemo4 {
    public static void main(String[] args) throws InterruptedException {
        /*
         String getName()   返回此线程的名称
        void setName(String name)   设置线程的名字(构造方法也可以设置名
        细节:
        1、如果我们没有给线程设置名字,线程也是有默认的名字的
            格式:Thread-X(X序号,从0开始的)
        2、如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置

        static Thread currentThread()   获取当前线程的对象
        static void sleep(long time)    让线程休眠指定的时间,单位为毫秒


         */

        // 1。创建线程的对象
        MyThread mt1 = new MyThread("飞机");
        MyThread mt2 = new MyThread("大炮");


        // 设置优先级
        mt1.setPriority(10);
        mt2.setPriority(1);
        

        // 2。开启线程
        mt1.start();
        mt2.start();
        /*
        // 3.获取线程
        Thread thread = Thread.currentThread();
        String name = thread.getName();
        System.out.println(name);
         */
        /*
        // 线程睡眠
        System.out.println("111111111");
        long startTime = System.currentTimeMillis();
        Thread.sleep(3000);
        System.out.println("222222222");
        System.out.println((System.currentTimeMillis() - startTime));
         */
    }
}

(三)setPriority和getPriority

更改线程优先级,最小是1,最大是10,优先级越大越有可能抢占到CPU时间,默认是5。

线程的调度,一般有2种:

l抢占式调度

l非抢占式调度

Java中采用抢占式调度的方法,随机性高,线程的优先级越高就越有可能抢到CPU执行时间。因此,优先级高的线程只是获得CPU时间的可能性更高,但是也有可能低优先级的线程排在高优先级的线程前执行。

(二)setDaemon(boolean on)

将此线程标记为守护线程或用户线程。当运行的线程都是守护线程时,Java虚拟机退出。必须在启动线程之前调用此方法。

当其他的非守护线程执行完毕之后,守护线程会陆续结束,这意味着守护线程不一定会按照代码指定的方式执行结束,很有可能守护线程执行到中途就会被退出。

public class ThreadDemo5 {
    public static void main(String[] args) {
        /*
            final void setDaemon(boolean on) 设置为守护线程
            细节:
                当其他的非守护线程执行完毕之后,守护线程会陆续结束
            通俗易懂的理解:
                当女神线程结束了,那么备胎也没有存在的必要了
         */

        // 创建线程对象
        MyThread01 t1 = new MyThread01(5);
        MyThread01 t2 = new MyThread01(20);

        // 命名线程
        t1.setName("被偏爱的");
        t2.setName("备胎");

        // 把第二个线程设置为守护线程
        t2.setDaemon(true);

        // 开启线程
        t1.start();
        t2.start();
    }
}

MyThread01类的代码:

public class MyThread01 extends Thread{
    private int count = 0;

    public MyThread01(int count){
        this.count = count;
    }

    public MyThread01(){
        this.count = 100;
    }

    @java.lang.Override
    public void run() {
        // 线程要执行的代码
        for (int i = 0; i < count; i++) {
            System.out.println(getName() + ": hello world." + i);
        }
    }
}

以上代码中,t1线程只需要执行5次即完成,而t2守护线程需要执行20次,当t1执行完毕后,t2作为守护线程会陆续退出,一般执行不到20次即会退出。

一次运行的结果:

备胎: hello world.0
备胎: hello world.1
备胎: hello world.2
被偏爱的: hello world.0
备胎: hello world.3
被偏爱的: hello world.1
备胎: hello world.4
被偏爱的: hello world.2
备胎: hello world.5
被偏爱的: hello world.3
备胎: hello world.6
被偏爱的: hello world.4
备胎: hello world.7
备胎: hello world.8
备胎: hello world.9

备胎线程运行了9次即退出了。

(三)yield方法

yield方法表示交出当前线程的执行权。

public class MyThread extends Thread{
    public MyThread(String name){
        super(name);
    }

    public MyThread(){
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            /*
            try {
                // 休眠1秒钟
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
             */
            // 要执行的代码
            System.out.println(getName() + (i + 1));
            // 表示出让cpu的执行权
            Thread.yield();
        }
    }
}

执行代码:

public class ThreadDemo6 {
    public static void main(String[] args) {
        MyThread mt1 = new MyThread("飞机");
        MyThread mt2 = new MyThread("大炮");

        // 执行
        mt1.start();
        mt2.start();
    }
}

以上代码在运行时会更加均匀的分次执行。

(四)join方法

join方法表示把当前线程插入到某个线程之前进行执行。

public class MyThreadJoin extends Thread{
    public MyThreadJoin(String name){
        super(name);
    }

    public MyThreadJoin(){
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            // 要执行的代码
            System.out.println(getName() + "@" + (i + 1));
        }
    }
}

执行代码:

public class MyThreadJoinDemo {
    public static void main(String[] args) throws InterruptedException {
        /*
            public final void join() 插入线程/插队线程
         */

        MyThreadJoin mtj = new MyThreadJoin();
        mtj.setName("土豆");
        mtj.start();

        // 表示把mtj这个线程,插入到当前线程之前
        // mtj:土豆线程
        // 当前线程:即是main线程
        mtj.join();

        // 在main线程中执行
        for (int i = 0; i < 10; i++) {
            System.out.println("main线程@" + i);
        }
    }
}

一、线程的生命周期

问:sleep方法会让线程睡眠,睡眠时间到了之后,立马就会执行下面的代码吗?

答:不一定,睡眠结束后线程进入就绪状态,需要抢夺到执行权之后才会继续执行。

相关文章