多线程之Thread类的基本用法

观前提示:本篇博客演示使用的 IDEA 版本为2021.3.3版本,使用的是Java8(又名jdk1.8)

1.线程创建

1.1 继承Thread 重写 run

class MyThreadDemo1 extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("Hello Thread");
            try {
                // 加入sleep,是为了让他打印慢一点,便于观察
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

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

首先创建一个类,由这个类去继承Thread类,重写其中的run方法

run方法: 创建出来的线程去执行的内容

start方法:  创建出一个新的线程,并让其去执行run方法里面的内容

sleep方法: sleep方法是Thread类中的一个静态方法,它可以让线程进入短暂休息的状态,比如sleep(1000) 就是休息1秒.(注意:sleep方法需要处理异常)

执行上面的代码,可能会出现以下几种情况

1.出现 Hello Thread 和 Hello 交替打印的情况(又分为两种,第一个是 Hello Thread 先打印,第二个是Hello 先打印)

2.只打印 Hello Thread

3.只打印 Hello 

这是因为执行完 t.start 之后会创建出来一个线程(暂且叫他 t 线程) t 线程和 main 线程同属于在同一个进程上,他们在操作系统上可能是并发,可能是并行,所以打印的顺序是无法预知的.

1.2 实现 Runnable, 重写 run

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("Hello Runnable");
    }
}

public class MyThread2 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        Thread t= new Thread(runnable);
        t.start();
    }
}

首先创建一个类,实现 Runnable 接口,重写里面的run方法.

将 Runnable 对象传到 Thread 的构造方法中,然后 t.start() 线程就创建好了.

1.3 继承 Thread, 重写 run,使用匿名内部类

public class MyThread3 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("Hello Thread");
            }
        };
        t.start();
    }
}

使用了匿名内部类 

1.4 实现 Runnable.重写 run,使用匿名内部类

public class MyThread4 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("Hello Thread");
            }
        };
        t.start();
    }
}

将类实现替换成内部类实现

1.5 使用lanbda 表达式

public class MyThread5 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            System.out.println("Hello Thread");
        });
        t.start();
    }
}

大括号里面的内容就相当于重写run方法的内容

2.线程中断

中断的意思是:不是让线程立刻停止,而是告诉线程,你该停止了,是否真的停止,取决于线程这里具体的代码写法

第一种:使用标志位来控制线程是否要终止

private static boolean flag = true;

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (flag) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = false;
    }

我们设置了一个 boolean 类型的静态成员变量,用来实现对 t 线程的控制,实现中断效果

第二种:使用Thread自带的标志位来控制线程是否停止

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        Thread.sleep(3000);
        t.interrupt();
    }


//Thread.currentThread().
//这是Thread类的静态方法,通过这个方法可以获取到当前线程
//那个线程调用这个方法,就得到那个线程对象的引用
//这个静态方法在 run 中被调用,获取的就是 t 线程

//isInterrupted()
//为 true 表示被终止
//为 false 表示未被终止

//t.interrupt()
//代表可以终止线程
//isInterrupted() 相当于一个 boolean 变量
//t.interrupt() 就是控制变量的

//interrupt会做两件事
//1.把线程内的标志位 (boolean) 设置成 true
//2.如果线程在进行 sleep 就会触发异常,把 sleep 唤醒
//但是, sleep 唤醒的时候,还会顺手把刚才设置的标志位再设置回 false (清空标志位)

 此代码运行调用了 Thread 自带的标志位来控制线程是否停止,运行代码我们会发现,他虽然抛出了一个异常,但是代码依然会继续往下运行,这就是前面所说的:"中断的意思是:不是让线程立刻停止,而是告诉线程,你该停止了,是否真的停止,取决于线程这里具体的代码写法"

下面在放一个实现了中断的代码写法

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //加上这段代码,代码会真的中断
                    try {
                        //0.5s后中断
                        Thread.sleep(500);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    break;
                }
            }
        });
        t.start();
        Thread.sleep(3000);
        t.interrupt();
    }

3.线程等待

线程是随机调度的过程

等待线程做的事情,就是在控制两个线程的结束顺序

 public static void main(String[] args) {
        Thread t = new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        System.out.println("join 之前" );
        // 此处的 join 就是让当前的 main 线程来等待 t 线程执行结束(等 run 结束)
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("join 之后");
    }

//t.start() 执行完以后, t 线程和 main 线程,并发执行,分头行动
//t 线程和 main 线程都往下执行, t 遇到 join, 发生阻塞(block)
//此时 main 线程就会阻塞等待,一直等待 t 线程的 run 执行完
//main 线程才会从 join 恢复过来

 

打印效果就是上面说的, 先打印 "join 之前", t 遇到 join 之后, main 线程开始阻塞等待, 然后 t 线程的 run 开始执行,打印 "hello thread",打印三遍,run 执行完,main 继续往下执行,打印"join 之后"

4.线程休眠

顾名思义:就是让线程休眠一下

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

 代码效果就是隔1s打印一条"hello thread"

5.获取线程实例

Thread.currentThread()方法

它是一个类方法,作用是获取当前线程的实例

也就是说: 你在哪个线程中去调用这个方法,那么它就会返回这个线程的实例对象.

 public static void main(String[] args) {
        Thread t = new Thread(()->{
            System.out.println(Thread.currentThread().getName());
        },"t 线程");
        t.start();
    }

本文完,感谢观看,有什么错误和不足的地方请在评论区指出,一起进步,谢谢 !

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值