2022年了,你还不会Java多线程吗?

1.什么是多线程?

Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。

这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。

多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。


2.线程的基本使用

Java中创建线程有两种方式:

  • 通过继承Thread类,重写run方法,创建线程
  • 实现Runnable接口,重写run方法,创建线程

通过继承Thread类创建线程代码示例:(此程序的任务是开启一个猫猫线程,该线程循环8此打印输出我是修猫🐱,随后结束)

/**
 * 多线程的基本使用
 * 通过继承Thread类创建线程
 */
public class ThreadUse {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.start(); // 启动线程
 
    }
}

/**
 * 继承Thread
 * 该类就可以当作线程使用
 */
class Cat extends Thread {
    // 重写run方法,写自己的业务
    // run方法实现了Runnable接口的run方法
    @Override
    public void run() {
        int times = 0;
        while (true) {
            System.out.println("我是修猫🐱" + (++times));
            // 让线程休眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (times == 8) {
                break;
            }
        }
    }
}

3.多线程控制机制

当我们开启一个线程类时,程序的调度机制时这样的:

在这里插入图片描述

此时如果CPU是多核就是并行执行,单核就是并发执行🐒

当程序启动一个子线程 Thread-0 ,主线程不会阻塞,会继续执行,主线程结束,Thread-0线程还未结束时,不会影响Thread-0执行,例如:

/**
 * 多线程的基本使用
 * 通过继承Thread类创建线程
 */
public class ThreadUse {
    public static void main(String[] args) throws InterruptedException {
        Cat cat = new Cat();
        cat.start(); // 启动线程
        // 当程序自动一个子线程 Thread-0 ,主线程不会阻塞,会继续执行
        System.out.println("我还可以被输出!");
        Thread.sleep(2000);
        System.out.println("我是修狗🐕");
    }
}

/**
 * 继承Thread
 * 该类就可以当作线程使用
 */
class Cat extends Thread {
    // 重写run方法,写自己的业务
    // run方法实现了Runnable接口的run方法
    @Override
    public void run() {
        int times = 0;
        while (true) {
            System.out.println("我是修猫🐱" + (++times));
            if (times == 1){
                System.out.println(Thread.currentThread().getName());
            }
            // 让线程休眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (times == 8) {
                break;
            }
        }
    }
}
----------------------------------
输出:
我还可以被输出!
我是修猫🐱1
Thread-0
我是修猫🐱2
我是修狗🐕
我是修猫🐱3
我是修猫🐱4
我是修猫🐱5
我是修猫🐱6
我是修猫🐱7
我是修猫🐱8

4.start源码分析

当我们触发一个线程的时候,需要使用start而非直接在主线程调用方法

现在我们来看一下start底层的真面目

public synchronized void start() {
    if (this.threadStatus != 0) {
        throw new IllegalThreadStateException();
    } else {
        this.group.add(this);
        boolean started = false;

        try {
            this.start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    this.group.threadStartFailed(this);
                }
            } catch (Throwable var8) {
            }
        }
    }
}

start源码里面,真正触发多线程的是此句话:

this.start0();

它是一个本地方法,由JVM机进行调用,底层是C/C++实现

真正实现多线程的效果,其实是strat0方法,而不是run方法🦍


5.实现Runnable接口创建线程

java是单继承的,某些情况一个类可能已经继承了某一个父类,那么再通过继承Thread类来实现多线程,显然是不可行的

此时我们可以使用实现Runnable接口来创建线程

/**
 * 通过继承Runnable接口实现多线程
 */
public class ThreadUseByRunnable {
    public static void main(String[] args) throws InterruptedException {
        Dog dog = new Dog();
        // 通过创建Thread类传入dog从而执行线程
        Thread thread = new Thread(dog);
        thread.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程" + i);
            Thread.sleep(1000);
        }
    }
}

/**
 * 通过实现Runnable接口实现多线程
 */
class Dog implements Runnable {

    int count = 0;

    @Override
    public void run() {
        while (true) {
            System.out.println("小狗旺旺🐕" + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            if (count == 8) {
                break;
            }
        }
    }
}

6.多个子线程实例

/**
 * 多个子线程案例
 */
public class ChildThreads {
    public static void main(String[] args) {
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread thread = new Thread(t1);
        Thread thread1 = new Thread(t2);
        thread.start();
        thread1.start();
    }
}

class T1 implements Runnable {
    int times = 0;
    @Override
    public void run() {
        // 每隔1秒输出一次hello world
        while (true) {
            System.out.println("hello world" + (++times));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (times == 8) {
                break;
            }
        }
    }
}

class T2 implements Runnable {
    int times = 0;
    @Override
    public void run() {
        while (true) {
            System.out.println("hi" + (++times));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (times == 8) {
                break;
            }
        }
    }
}
-------------------------------
两个线程交替输出:
hello world1
hi1
hello world2
hi2
hello world3
hi3
hello world4
hi4
hello world5
hi5
hello world6
hi6
hello world7
hi7
hello world8
hi8

存在多个子线程时,系统的调度结构如下:

在这里插入图片描述

Thread VS Runnable🦧(建议使用Runnable

  • 创建线程本质上没有区别,都是通过strat0方法
  • Runnable接口更加适合多个线程共享一个资源的情况,并且避免的单继承的限制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

世界尽头与你

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

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

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

打赏作者

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

抵扣说明:

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

余额充值