怀旧网,博客详情:Java 多线程使用介绍

1、java枚举类详解

2、java String 类和类方法详解

3、StringBuffer 详解

4、Java Math 类详解

5、java random详解

6、java Date类使用讲解

7、java 集合类详解

8、java算法二分查找

9、SpringBoot 在初始化加载无法使用@Value的时候读取配置文件教程

10、springboot 项目配置本地jar包导入

11、单个java文件运行需要带上jar包的用法

12、spring boot 项目配置https服务

13、Java异常详解

14、Java Collection的使用

15、Java List 集合

16、Java ArrayList 介绍

17、Java LinkedList 讲解

18、Java Set 集合介绍

19、Java HashSet 介绍

20、Java TreeSet 介绍

21、Java Map 介绍以及子类介绍

22、Java 多线程使用介绍

23、Java 注解讲解

24、Java 反射讲解

25、Java 反射讲解

26、HashMap 源码讲解

27、面向对象初级教学

28、Java整合JWT使用

原创

Java 多线程使用介绍

线程简介

任务

image-20240318192029773

案例1:在吃饭的时候,边吃饭边玩手机

image-20240318192053805

案例2:也可以边上厕所边玩手机

多任务处理是指用户可以在同一时间内运行多个应用程序,每个应用程序被称作一个任务.Linux、windows就是支持多任务的操作系统,比起单任务系统它的功能增强了许多。

当多任务操作系统使用某种任务调度策略允许两个或更多进程并发共享一个处理器时,事实上处理器在某一时刻只会给一件任务提供服务。因为任务调度机制保证不同任务之间的切换速度十分迅速,因此给人多个任务同时运行的错觉。多任务系统中有3个功能单位:任务、进程和线程。

进程

image-20240318192628409

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

线程

例如在一个抢票网站中,100张票,有1000个人来抢,然而这1000个人其中每个人就可以理解为一个线程。

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如[Windows 7](https://baike.baidu.com/item/Windows 7/0?fromModule=lemma_inlink)的线程,进行混合调度。

同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。

一个进程可以有很多线程,每条线程并行执行不同的任务。

在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。

多线程

image-20240318192420743

多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机多核心处理器以及芯片级多处理同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理” [1]。

image-20240318192504192

进程和线程的区别

image-20240318192952502

总结

image-20240318193253150

多线程的实现

线程的创建方式

  • 继承 Thread 类(常用)
  • 实现 Runnable 接口(常用--核心)
  • 实现 Callable 接口(不常用)

继承 Thread 实现方式

当没有线程的情况

for (int i = 0; i < 50; i++) {
    System.out.println("newThread " + i);
}

for (int i = 0; i < 50; i++) {
    System.out.println("main " + i);

image-20240318194745606

这边是当上面的代码全部执行完毕,才回执行后面的代码

创建方式-运行主类继承 Thread 类, 并重写 run 方法,最后调用 start 方法开启线程

public class Test2 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("newThread " + i);
        }
    }

    public static void main(String[] args) {
        Test2 test2 = new Test2();
        test2.start();

        for (int i = 0; i < 50; i++) {
            System.out.println("main " + i);
        }
    }
}

image-20240318194346923

可以看到其中有代码穿插的情况

注意:由于继承的局限性,需要考虑好使用情况

实现 Runnable 接口

实现方式:编写类,实现 Runnable 接口,重写run方法,调用时需要new Thread对象,并将实现 Runnable 接口的实例化对象传入,并调用Thread的start方法,来运行线程

下面是代码演示:

public class Test2 extends Thread{
    public static void main(String[] args) {
        new Thread(new ThreadTest()).start();

        for (int i = 0; i < 50; i++) {
            System.out.println("main " + i);
        }
    }
}

class ThreadTest implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("newThread " + i);
        }
    }
}

image-20240318204642746

简化写法-采用Lambda表达式

public static void main(String[] args) {
    new Thread(()->{
        for (int i = 0; i < 100; i++) {
            System.out.println("newThread " + i);
        }
    }).start();

    for (int i = 0; i < 100; i++) {
        System.out.println("main " + i);
    }
}

image-20240319104807353

实现 Callable 接口

实现方式1:

public class Test2{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> stringFutureTask = new FutureTask<>(new TestCallable());
        new Thread(stringFutureTask).start();
        String s = stringFutureTask.get();
        System.out.println(s);
    }
}

class TestCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        return "你好!";
    }
}

image-20240319213354868

实现方式2:

image-20240319104950329

public class Test2{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建线程池对象
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 创建线程执行对象
        TestCallable t1 = new TestCallable();
        TestCallable t2 = new TestCallable();

        // 提交线程对象到线程池-并获取到执行结果
        Future<String> submit1 = executorService.submit(t1);
        Future<String> submit2 = executorService.submit(t2);

        // 获取返回值数据
        String res1 = submit1.get();
        String res2 = submit2.get();

        // 输出返回值
        System.out.println(res1);
        System.out.println(res2);

        // 关闭线程池对象
        executorService.shutdownNow();
    }
}

class TestCallable implements Callable<String>{
    @Override
    public String call() throws Exception {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 100; i++) {
            System.out.println(name + " " + i);
        }

        return name;
    }
}

image-20240319105849851

image-20240319105909436

public class Test2{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建线程池对象
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // 创建线程执行对象
        TestCallable t1 = new TestCallable();

        // 提交线程对象到线程池
        for (int i = 0; i < 10; i++) {
            executorService.submit(t1);
        }

        // 关闭线程池对象
        executorService.shutdownNow();
    }
}

class TestCallable implements Callable<String>{
    @Override
    public String call() throws Exception {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 1000; i++) {
            System.out.println(name + " " + i);
        }

        return name;
    }
}

image-20240319110243034

总结:

  1. 可以定义返回值
  2. 默认可以帮我们调度管理多线程
  3. 可以抛出异常

多线程底层实现方式

  1. 创建实际对象和代理对象
interface Eat{
    void eat();
}

class My implements Eat{

    @Override
    public void eat() {
        System.out.println("我吃饭了!!");
    }
}

class EatAgent implements Eat{
    private My user;

    public EatAgent(My user) {
        this.user = user;
    }

    @Override
    public void eat() {
        before();
        user.eat();
        after();
    }

    private void before(){
        System.out.println("准备食材做饭·");
    }

    private void after(){
        System.out.println("你吃完了,收钱,收拾残局·");
    }
}
  1. 测试没有代理时的情景
My my = new My();
my.eat();

image-20240319110924817

  1. 使用代理来实现吃饭效果
My my = new My();

EatAgent eatAgent = new EatAgent(my);

eatAgent.eat();

image-20240319111006514

  1. 简化代码
new EatAgent(new My()).eat();

image-20240319111046634

  1. 查看多线程实现代码对比

image-20240319111148069

底层实现就是采用代理的形式进行的。

线程状态

线程一共有五大状态如下:

image-20240319112425014

image-20240319112554703

image-20240319112719686

线程停止方式

建议:

  1. 建议让线程正常停止 ----> 利用计数器,不建议写死循环。
  2. 建立使用标志位 ----> 设置一个停下的标准。
  3. 不建议使用已经过时的方法:stop 和 destroy 。

测试案例:

public class Test2 implements Runnable{
    public static void main(String[] args){
        Test2 thread = new Test2();
        new Thread(thread, "线程1").start();

        for (int i = 0; i < 1000; i++) {
            if(i == 800){
                System.out.println("主线程到800次,让线程停止!");
                thread.stop();
            }
            System.out.println("主线程执行 --> " + i);
        }
    }

    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while(flag){
            System.out.println(Thread.currentThread().getName() + " -- > " + i++);
        }
    }

    public void stop(){
        flag = false;
    }
}

image-20240319113724427

线程休眠

image-20240319114225498

模拟抢票同时操作一个线程

public class Test2 implements Runnable{
    private int ticketNum = 10;

    public static void main(String[] args){
        Test2 thread = new Test2();
        new Thread(thread, "小红").start();
        new Thread(thread, "小黄").start();
        new Thread(thread, "小花").start();
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if(ticketNum > 0){
                System.out.println(Thread.currentThread().getName() + "抢了第 " + ticketNum-- + "张票~");
            }else{
                break;
            }
        }
    }
}

image-20240319140201105

当线程在运行的时候有了阻塞的时候,就可能会出现上面的情况。

所以模拟延时可以方法问题的发生性。

线程礼让

image-20240319140930359

礼让情景测试(Thread.yield() 可以开启礼让)

没有礼让情况

public class Test2 implements Runnable{
    public static void main(String[] args){
        Test2 thread = new Test2();
        new Thread(thread, "a").start();
        new Thread(thread, "b").start();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "--开始");
        System.out.println(Thread.currentThread().getName() + "--结束");
    }
}

image-20240319141626734

public class Test2 implements Runnable{
    public static void main(String[] args){
        Test2 thread = new Test2();
        new Thread(thread, "a").start();
        new Thread(thread, "b").start();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "--开始");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + "--结束");
    }
}

礼让成功

image-20240319141509447

礼让失败

image-20240319141723474

Join 合并线程

可以将这个理解为插队,当当前的线程执行过join方法后就会强制先执行完当前线程,后续才回执行其他线程。

案例:

public class Test2 implements Runnable{
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Test2());
        thread.start();

        for (int i = 0; i < 200; i++) {
            Thread.sleep(1);
            if(i == 30){
                thread.join();
            }
            System.out.println("main --> " + i);
        }
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                Thread.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " --> " + i);
        }
    }
}

image-20240319142514398

image-20240319142537933

当main执行到30的时候,我们的线程就开始调用join了。开始插队。

image-20240319142618782

当线程跑完了后,主线程才接着执行。

线程在运行时的几个状态

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(()->{
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });

    Thread.State state = thread.getState();
    System.out.println(state);

    thread.start();
    state = thread.getState();
    System.out.println(state);

    while (true){
        Thread.sleep(100);
        state = thread.getState();
        System.out.println(state);

        if(Thread.State.TERMINATED == state){
            break;
        }
    }
}

image-20240319144714881

注意:在线程到结束转台就不可以在去调用start了,否则就会报错

image-20240319144437526

线程的优先级

当有的线程比较重要需要先执行的时候,就可以给线程设置优先级(被设置优先级很高的线程更容易先执行)

线程的等级为1~10默认的优先级为5

public class Test2 implements Runnable{
    public static void main(String[] args) {
        Test2 test2 = new Test2();

        Thread t1 = new Thread(test2);
        Thread t2 = new Thread(test2);
        Thread t3 = new Thread(test2);
        Thread t4 = new Thread(test2);
        Thread t5 = new Thread(test2);
        Thread t6 = new Thread(test2);

        // 主线程默认等级为 5
        System.out.println(Thread.currentThread().getName() + " --> " + Thread.currentThread().getPriority());

        t2.setPriority(1);
        t3.setPriority(4);
        t4.setPriority(Thread.MAX_PRIORITY); // 10
        t5.setPriority(8);
        t6.setPriority(3);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " --> " + Thread.currentThread().getPriority());
    }
}

image-20240319150639652

当设置后,优先级较高的会被优先执行(但是不保真-相当于你 9/10 概率 他1/10 概率,但是还是有可能他中奖)

守护线程(daemon)

image-20240319151006745

守护线程的作用就是和用户线程区分开的一种特殊的线程,即使守护线程没有执行完毕,程序依然会结束。

启动守护线程需要调用setDaemon 方法传入 true就开始守护线程了--默认值为false不开始守护线程

测试:

public static void main(String[] args) {
    Thread t1 = new Thread(()->{
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("用户线程执行 --> " + i);
        }
    });

    Thread t2 = new Thread(()->{
        for (int i = 0;; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("守护线程执行 --> " + i);
        }
    });

    // 将线程设置为守护线程
    t2.setDaemon(true);

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

image-20240319151730225

这里可以看到我们设置的守护进程为永真,但是在用户线程执行完毕后,守护线程没有执行完,但是程序依然结束了,这就是守护线程的作用。

线程同步

image-20240319152634978

并发

有多个线程同时来操作同一个数据,就称为并发。

例如前面讲的案例,多人同时去购买一张票,就会导致出现票数为负数的情况。

线程不安全案例:

public class Test2 implements Runnable{
    private int money = 200;

    public static void main(String[] args) {
        Test2 test2 = new Test2();

        new Thread(test2, "a").start();
        new Thread(test2, "b").start();
        new Thread(test2, "c").start();
    }

    @Override
    public void run() {
        if (money > 0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            money -= 100;
            System.out.println(Thread.currentThread().getName() + "-->" + 100);
            System.out.println("余额:" + this.money);
        }
    }
}

image-20240319161527825

案例二:

public static void main(String[] args) throws InterruptedException {
    List<Integer> list = new ArrayList<>();

    for (int i = 0; i < 10000; i++) {
        new Thread(()->list.add(1)).start();
    }

    Thread.sleep(3000);
    System.out.println(list.size());
}

image-20240319161919953

ArrayList 就是一个线程不安全的案例,当多线程去往里面添加数据的时候,可能会操作到同一个数据导致添加失败~

队列

队列就是让所有线程来操作对象的时候,就不能同时的去操作对象数据,

需要进行排序,前面的操作完了,后面的才可以在去进行操作。

优点:可以让数据变为安全,不会出现数据异常的情况

缺点:效率会大大降低

锁就是为了实现队列这个效果二产生的,目的就是锁住可能会被多人同时操作的对象,让他们有序排序,不能一起来操作

锁的实现方式

  1. 通过 synchronized 直接锁住一个方法,直接在方法上面添加 synchronized 关键字,就可以锁住一个方法,被锁住的方法就需要一个一个一次执行。
public class Test2 implements Runnable{
    private int money = 200;

    public static void main(String[] args) {
        Test2 test2 = new Test2();

        new Thread(test2, "a").start();
        new Thread(test2, "b").start();
        new Thread(test2, "c").start();
    }

    @Override
    public synchronized void run() {
        if (money > 0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            money -= 100;
            System.out.println(Thread.currentThread().getName() + "-->" + 100);
            System.out.println("余额:" + this.money);
        }else{
            System.out.println("余额不足了!");
        }
    }
}

image-20240319163526568

不论运行多少次,都不会在出现为负数的这种情况了。

  1. synchronized 锁对象的方式,这种方式是锁住了一个对象,被锁住的这个对象在代码块中操作obj的时候,就会需要排队,一个一个执行。

image-20240319164904892

案例(解决集合添加问题):

public static void main(String[] args) throws InterruptedException {
    List<Integer> list = new ArrayList<>();

    for (int i = 0; i < 10000; i++) {
        new Thread(()->{
            synchronized (list){
                list.add(1);
            }
        }).start();
    }

    Thread.sleep(1000);
    System.out.println(list.size());
}

image-20240319164304890

当对象被锁后,不论怎么操作都不会影响数据的完整性。

死锁

image-20240319165420166

代码示例:

public class Test2 implements Runnable{
    public static String compute = "电脑";
    public static String phone = "手机";
    public boolean flag;

    public Test2(boolean flag) {
        this.flag = flag;
    }

    public static void main(String[] args){
        Test2 t1 = new Test2(false);
        Test2 t2 = new Test2(true);

        new Thread(t1, "我").start();
        new Thread(t2, "你").start();
    }

    @Override
    public void run() {
        if(flag){
            synchronized (compute){
                System.out.println(Thread.currentThread().getName() + "拿到了" + compute + "的锁");

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

                synchronized (phone){
                    System.out.println(Thread.currentThread().getName() + "拿到了" + phone + "的锁");

                }
            }
        }else{
            synchronized (phone){
                System.out.println(Thread.currentThread().getName() + "拿到了" + phone + "的锁");

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

                synchronized (compute){
                    System.out.println(Thread.currentThread().getName() + "拿到了" + compute + "的锁");

                }
            }
        }
    }
}

image-20240319170807965

运行之后代码会一直卡死:

​ 原因是当前的我拿到了手机的锁--然后你拿到了电脑的锁,我现在又想接着去拿电脑的锁,但是发现你拿了,所以我就需要等待,然后你也需要拿手机的锁,你也在等我,所以就导致了你等我-我等你--最终代码程序锁死。

下面是解决方案:

​ 我们可以让一个线程一次性别拿多吧锁,先吧手中的锁释放了在去拿新的,就可以解决这个问题。

public class Test2 implements Runnable{
    public static String compute = "电脑";
    public static String phone = "手机";
    public boolean flag;

    public Test2(boolean flag) {
        this.flag = flag;
    }

    public static void main(String[] args){
        Test2 t1 = new Test2(false);
        Test2 t2 = new Test2(true);

        new Thread(t1, "我").start();
        new Thread(t2, "你").start();
    }

    @Override
    public void run() {
        if(flag){
            synchronized (compute){
                System.out.println(Thread.currentThread().getName() + "拿到了" + compute + "的锁");
            }

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

            synchronized (phone){
                System.out.println(Thread.currentThread().getName() + "拿到了" + phone + "的锁");
            }
        }else{
            synchronized (phone){
                System.out.println(Thread.currentThread().getName() + "拿到了" + phone + "的锁");
            }

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

            synchronized (compute){
                System.out.println(Thread.currentThread().getName() + "拿到了" + compute + "的锁");
            }
        }
    }
}

image-20240319171115732

修改代码,完成测试!

死锁的避免方法:

image-20240319170118625

扩展锁

线程不安全测试代码:

public class Test2{
    public static void main(String[] args) {
        LockTest lockTest = new LockTest();

        new Thread(lockTest).start();
        new Thread(lockTest).start();
        new Thread(lockTest).start();
    }
}

class LockTest implements Runnable{
    private int ticketNum = 10;

    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            if (ticketNum > 0){
                System.out.println(Thread.currentThread().getName() + " --> " +ticketNum--);
            }else{
                break;
            }
            
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

image-20240319174619266

可能会操作到同一个对象

采用Locl锁后:

public class Test2{
    public static void main(String[] args) {
        LockTest lockTest = new LockTest();

        new Thread(lockTest).start();
        new Thread(lockTest).start();
        new Thread(lockTest).start();
    }
}

class LockTest implements Runnable{
    private int ticketNum = 10;

    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            lock.lock();
            if (ticketNum > 0){
                System.out.println(Thread.currentThread().getName() + " --> " +ticketNum--);
            }else{
                break;
            }
            lock.unlock();
            
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

image-20240319174722063

推荐写法

public class Test2{
    public static void main(String[] args) {
        LockTest lockTest = new LockTest();

        new Thread(lockTest).start();
        new Thread(lockTest).start();
        new Thread(lockTest).start();
    }
}

class LockTest implements Runnable{
    private int ticketNum = 10;

    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try {
                lock.lock();
                if (ticketNum > 0){
                    System.out.println(Thread.currentThread().getName() + " --> " +ticketNum--);
                }else{
                    break;
                }
            }finally {
                lock.unlock();
            }

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

对比

image-20240319174934163

线程通信问题

image-20240319192948391

image-20240319193011923

生产者消费者模式?

image-20240319192821214

代码实现生产者消费者

public class Test2{
    public static void main(String[] args) {
        SynContainer synContainer = new SynContainer();

        Producer producer = new Producer(synContainer);
        Consumer consumer = new Consumer(synContainer);

        new Thread(producer).start();
        new Thread(consumer).start();

    }
}

// 生产者
class Producer implements Runnable{
    public SynContainer synContainer;

    public Producer(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

    // 生产
    @Override
    public void run() {
        for (int i = 1; i < 101; i++) {
            synContainer.producer(new Fish(i));
            System.out.println("生产了第 " + i + " 个产品!");
        }
    }
}

class Consumer implements Runnable{
    public SynContainer synContainer;

    public Consumer(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

    // 消费
    @Override
    public void run() {
        for (int i = 1; i < 101; i++) {
            System.out.println("消费 --> " + synContainer.consumer().fishId + " 个产品!");
        }
    }
}

// 产品
class Fish{
    public int fishId;

    public Fish(int fishId) {
        this.fishId = fishId;
    }
}

// 缓冲区
class SynContainer{
    private Fish[] fishs = new Fish[10];
    private int count = 0;

    public SynContainer() {
    }

    // 生产
    public synchronized void producer(Fish fish){
        // 如果产品满了
        if(count == fishs.length){
            // 停止生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 生产产品
        fishs[count++] = fish;

        // 提醒用户可来取
        this.notify();
    }

    // 消费
    public synchronized Fish consumer(){
        // 如果当前没有产品了
        if(count == 0){
            // 停止消费--需要等待生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 开始消费
        Fish fish = fishs[--count];

        // 通知生成者生产
        this.notify();

        return fish;
    }
}

image-20240319202034174

高级主题

线程池

image-20240319211839452

线程池的使用

image-20240319211935866

线程池的使用:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test2 implements Runnable{
    public static void main(String[] args) {
        // 创建线程池对象--并指定创建10条线程
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // 添加线程需要执行的任务
        executorService.execute(new Test2());
        executorService.execute(new Test2());
        executorService.execute(new Test2());
        executorService.execute(new Test2());

        // 关闭线程池对象
        executorService.shutdownNow();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

image-20240319212540103

在上面的添加执行任务的时候可以使用execute(没有返回值),也可以使用submit(有返回值)

  • 平台作者:怀旧(联系作者)
  • QQ:444915368
  • 邮箱:444915368@qq.com
  • 电话:17623747368
  • 评论

    登录后才可以进行评论哦!

    回到顶部 留言