四万字爆肝总结java多线程所有知识点(史上最全总结)


全文从多线程的实现方式、线程的状态、线程的方法、线程的同步、线程的通讯、等角度对多线程的基础知识进行总结

一、多线程的实现方式

  • 继承Thread类,重写run方法
  • 实现Runnable接口,重写run方法
  • 实现Callable接口,重写call方法
    这是三种多线程的创建方式,此外我们创建多线程时可以使用多个Thread对象开启同一个Runnable接口实现类达到多线程的目的,也可以使用多个Thread对象开启多个Runnable实现类来达到多线程,这两种实现方法笔者思考了下,感觉都是有应用场景的,我们在购票系统中,投票的方法其实是多线程都需要调用的,我们就可以使用多个Thread开启同一个Runnable实现类的方式来实现多线程,只需要为卖票方法加锁即可。但若是有一个队列我们想要用多线程去处理队列里面的内容,此时就可以使用多个Thread开启多个Runnable实现类的方式来适用不同对象的不同处理方式,从而提高处理效率。

1.继承Thread类,重写run方法

这种实现方式是jdk1.0便已经存在了,实现也很简单,直接继承Thread,重写run方法,然后我们通过Thread对象的start方法启动即可。
示例代码如下:

public class Test1 extends Thread{
   
    @Override
    public void run() {
   
        while(true){
   
            System.out.println("线程1");
        }

    }

    public static void main(String[] args) {
   
        new Test1().start();
    }
}

2.实现Runnable接口,重写run方法

实现Runnable接口,其实与第一种实现方式本质上还是一样的,因为Thread就是实现了Runnable接口。当使用实现Runnable接口的方式实现多线程时,应该重写run方法。启动线程时使用Thread的start方法,示例代码如下:

public class TestThread {
   
    public static void main(String[] args) {
   
        new Thread(() -> {
   
            while(true)
                System.out.println("Runnable多线程1");
        }).start();
        
        new Thread(() -> {
   
            while(true)
                System.out.println("Runnable多线程2");
        }).start();
    }
}

3.实现Callable接口,重写call方法

Callable接口是JDK1.5加入的,位置在java并发包里面,他的功能比较强大支持异常的抛出线程执行结果的返回。这些都是前面两种实现方式所不具备的。前面两种能完成的实现Callable都可以完成,前面两种完不成的Callable也可以完成,所以没有理由不使用Callbale。示例代码如下:

public class TestThread {
   
    public static void main(String[] args) throws Exception{
   
        FutureTask<String> futureTask = new FutureTask<>(()->{
   
            int i =0 ;
            while(i<100)
                System.out.println("Callable线程1在执行:"+i++);
            return "线程1执行完了";
        });

        FutureTask<String> futureTask2 = new FutureTask<>(()->{
   
            int i =0 ;
            while(i<100)
                System.out.println("Callable线程2在执行:"+i++);
            return "线程2执行完了";
        });

        new Thread(futureTask).start();
        new Thread(futureTask2).start();
        System.out.println(futureTask.get());
        System.out.println(futureTask2.get());
    }
}

以上是三种多线程的实现方式,有人会把线程池也算成一种多线程的实现方式,笔者认为线程池并不能算是一种方式,他只是一种池化技术,这种技术在编程中有很多场景,底层还是使用的一样的技术而已。总结以上三种多线程的实现方式,

  • 可以发现Thread是最low的一种,因为他是基于继承来实现的,而java中类时不支持多继承的(接口可以多继承),所以他会影响到线程类的扩展性
  • 若是不需要线程的返回值建议使用Runnable方式,需要的话就只能选择Callable了
  • 所有线程的创建方式都需要依赖Thread类的start方法,说明该方法才是创建线程的真正方法,该方法也是一个native方法。
  • 因为所有线程的启动都需要依赖Thread,所以Thread中的方法可以说都是公用的,Thread也是很重要的

不过当下全是使用线程池来实现多线程技术,基本没有手动去创建线程的,所以线程池的使用和手动实现线程池才是应该注意的地方。

二、线程的状态

在这里插入图片描述

1.new状态

创建出Thread的对象后就是new的状态了。

2.就绪状态

Thread的start方法才是创建一个线程的根本,start方法调用native的实现去开启一个线程(可以发现无论哪种多线程的实现方式都需要Thread的start方法来开启线程),当这个start方法执行后线程就是new的状态了。

3.运行状态

运行状态就是线程在运行run方法或者call方法体中的内容了,线程在运行状态中可以进入到阻塞状态,也可以进入到就绪状态,比如yield就会让线程进入就绪状态,wait、sleep会让线程进入到阻塞状态。

4.阻塞状态

当现场争抢cpu时间片失败后就会进入到阻塞状态,阻塞状态中的线程需要等他其他线程释放cpu资源然后再一次和其他线程去争抢cpu的时间片,争抢成功则进入到运行状态,否则再次进入到阻塞状态。

5.死亡状态:线程如何正确的死亡

我们知道Thread已经提供了stop等方法用于停止一个线程或者说让一个线程死亡,但是stop方法是Dreprected的,是不推荐使用的,那我们该如何正确的停止一个线程呢?答案是在主线程中维护一个boolean变量,用这个变量控制线程的运行和死亡,比如如下代码:我们可以在适当的时候将flag置为false,这样线程也就结束了。此处有一点需要注意,volatile关键字修饰了flag,被volatile关键字修饰的变量一旦改变,会强制子线程中的该变量失效,子线程需要从主线程从新获取(可见性问题)。

public class TestThread {
   
    volatile static Boolean  flag = true;


    public static void main(String[] args) throws Exception{
   
        FutureTask<String> futureTask = new FutureTask<>(()->{
   
            int i =0 ;
            while(flag)
                System.out.println("Callable线程1在执行:"+i++);
            return "线程1执行完了";
        });

        new Thread(futureTask).start();
        System.out.println(futureTask.get());
    }
}

我们都知道

三、Thread中常用的方法

1.setPriority():

设置线程优先级
需要注意的是线程的优先级高也不一定就肯定先执行,只是优先级高的线程先执行的概率更大而已,优先级从1-10,10为最高,不设置默认为5,到底谁先执行与操作系统有关系,主要看操作系统对cpu的调度,示例代码如下:

public class TestThread {
   
    volatile static  Boolean  flag = true;

    public static void main(String[] args) throws Exception {
   
        Thread thread1 = new Thread(() -> {
   
            System.out.println("优先级为1的线程");
        });
        Thread thread2 = new Thread(() -> {
   
            System.out.println("优先级为3的线程");
        });
        Thread thread3 = new Thread(() -> {
   
            System.out.println("优先级为5的线程");
        });
        Thread thread4 = new Thread(() -> {
   
            System.out.println("优先级为7的线程");
        });
        Thread thread5 = new Thread(() -> {
   
            System.out.println("优先级为10的线程");
        });
        thread1.setPriority(1);
        thread2.setPriority(3);
        thread3.setPriority(5);
        thread4.setPriority(7);
        thread5.setPriority(10);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
    }
}

2.sleep():

让线程进入阻塞状态这个方法用过的人应该是非常多了,传入的是一个int型整数,代表毫秒。目的是让线程睡一会。该方法结束后线程进入就绪状态。值得注意的是每个线程都有一把锁,而sleep并不会释放这把锁。

3.join():

这是个插队的方法,他不是静态方法,需要使用Thread的对象来调用,当一个线程调用join方法时,该线程会强制抢占cpu资源,直到该线程执行完毕其他线程才会继续执行,示例代码如下:

public class TestThread {
   
    volatile static  Boolean  flag = true;

    public static void main(String[] args) throws Exception{
   
        Thread thread = new Thread(() -> {
   
            for (int i = 0; i < 1000; i++) {
   
                System.out.println("vip线程1:"+i);
            }
        });

        for (int i = 0; i < 500; i++) {
   
            System.out.println("主线程:"+i);
            if(i==200)
                thread.join();
        }

        thread.start();
    }

}

4.yield():

释放cpu资源,让当前线程进入就绪状态,礼让操作,重新和其他线程竞争cpu资源。需要说的是礼让并不一定成功。笔者多次测试都礼让成功了,看来礼让还是有效果的。示例代码如下:

public class TestThread {
   
    volatile static  Boolean  flag = true;

    public static void main(String[] args) {
   
        new Thread(() -> {
   
            int i = 0;
            while(i<100){
   
                if(i==50)
                    Thread.yield();
                System.out.println("线程1:"+i++);
            }
        }).start();

        new Thread(() -> {
   
            int i = 0;
            while(i<100)
                System.out
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

归去来 兮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值