Java学习_21_多线程JUC

news2024/11/13 10:54:44

文章目录

  • 前言
  • 多线程
    • 并发与并行
    • 多线程的实现方式
      • Thread类
      • Runnable接口
      • Callable接口和Future接口
    • Thread类的相关方法
      • 线程对象
      • 线程优先级
      • 守护线程
      • 出让线程/礼让线程
      • 插入线程/插队线程
    • 线程的相关问题
      • 生命周期
      • 安全问题
      • Lock锁
      • 死锁
      • 等待唤醒机制(生产者和消费者)
        • 通过阻塞队列实现
    • 综合练习
    • 线程池


前言

博客仅记录个人学习进度和一些查缺补漏。
学习内容:BV17F411T7Ao


多线程

首先需要知道什么是进程什么是线程,详见408《操作系统》
在这里插入图片描述
进程是程序执行的实体,是资源调度的基本单位,处理机分配给每一个程序的资源都以进程为整体。

在这里插入图片描述
线程是进程中的实际运行单位,也是资源调度的最小单位。
在这里插入图片描述
在这里插入图片描述
以前的代码都是单线程程序
在这里插入图片描述
为了提高CPU的运行效率,应该使用多线程程序

并发与并行

详见408,重点内容

并发 :指多个指令在单个CPU上交替执行
即在一定的时间周期内,多次进行作业调度,执行不同的指令

并行 :指多个指令在多个CPU上同时执行
即在同一时刻上,多个CPU同时执行不同的指令

并发和并行在当前的处理机环境下会同时发生

多线程的实现方式

在这里插入图片描述

Thread类

表示java中的一个线程,任何继承该类的子类都可以重写其run方法,提示为多线程程序。

例如:在run中书写要执行的代码,使用start来启动线程
在这里插入图片描述
例如:多线程同时启动,指同一个程序(打印helloworld的代码体只有一个)的两个不同线程(t1和t2)同时工作,其中getname是Thread类的内置方法
在这里插入图片描述

Runnable接口

实现Runnable接口再重写run方法,本质上是一种描述任务的方法,实际多线程还是通过Thread对象来执行。

例如:先定义一个类,再实现接口,再run中描述具体的任务,Runnable默认是多线程模式,可以直接获取当前线程的对象。
在这里插入图片描述

例如:创建Myrun对象,将任务发布,可以通过多个线程对象来同时进行任务并分开结算

在这里插入图片描述

Callable接口和Future接口

在这里插入图片描述

Callable接口提示该类为描述多线程任务类,再call中描述具体的任务,并且给出返回值,将任务发布给Thread类的对象来完成,并通过Future类的对象来取得call的结果。

例如:任务发布类
在这里插入图片描述
例如:找一个工会柜员来管理这个任务的结果,需要注意的是一个柜员可以对应多个完成者的结算,每次接收的都是最后一个完成者(线程)完成的结果
在这里插入图片描述
例如:找一个冒险者(线程)来完成这个任务,并通过柜员(Future)来管理结果
在这里插入图片描述
在这里插入图片描述

Thread类的相关方法

在这里插入图片描述

线程对象

例如:查看线程的默认名字
发布任务
在这里插入图片描述
对于继承了Thread的类来说,相当于任务实体本身就是可以完成任务的单位(只做固定任务的打工人),属于远征类任务,点一下自己就完成了,不需要额外分配thread类(冒险者)来完成。
在这里插入图片描述
此时线程是有自己的默认名字的
在这里插入图片描述
例如:如果要进行名字的设置,可以通过构造方法(需要自己重写)也可通过setname成员方法
在这里插入图片描述
如果没有手动执行线程,默认线程也是有名字的,即虚拟机默认的main线程

例如:sleep可以手动阻塞线程使其停留一段时间(改时间内会让出CPU,并设置一个计时器,时间到则会从挂起态恢复成就绪态。
在这里插入图片描述

线程优先级

抢占式调度:多线程抢夺执行权,执行顺序和执行时间都是不确定的(实际上就是优先级来看的,优先级越高能抢到的总时间占比就越大,当作业到来的时候能优先享用CPU)
非抢占式调度:新作业到达时只能排队,不能抢,大伙轮流依次使用CPU

JAVA中使用了抢占式调度,分为10个优先级
在这里插入图片描述
例如:查看默认优先级,包括main线程,java中默认线程优先级都是5
在这里插入图片描述
在这里插入图片描述
例如:设置优先级
在这里插入图片描述
优先级越大,抢占的CPU资源就多,就能更早的执行结束

守护线程

仅仅是为了执行同一个任务的主线程而存在的分线程,来源于同一个任务模块,当被设置成守护线程以后,会为真勇者铺路,真勇者任务结束了,即使自己的任务没有完成,也应该结束。
例如:会陆续结束而不是立即结束
在这里插入图片描述
例如此时,传输文件就是聊天的守护线程(分线程)
在这里插入图片描述

出让线程/礼让线程

由任务版本身提出限制,执行完一次任务后应当让出CPU,让各个执行任务的实体对象相互分配使用CPU
例如:
在这里插入图片描述

插入线程/插队线程

在申明了该方法后,将申明的线程调度到当前进程的前面,可以优先使用CPU
例如在原过程中,自定义线程和main线程并发执行,相互抢夺CPU使用权:
在这里插入图片描述
例如:申明了插队以后(在某一个线程内进行插队),可以比当前的进程更快执行
在这里插入图片描述

线程的相关问题

生命周期

详见408
在这里插入图片描述
在更新了阻塞锁的概念以后,添加了新的生命周期:

在这里插入图片描述

安全问题

多线程常常会出现临界资源共享顺序问题,如果进入临界区不上锁,会导致临界资源的出错
例如:
例如:将电影票设置为static,成为多线程共享的临界资源
在这里插入图片描述
但是因为临界区没有上锁,各线程之间随意进出临界区,导致临界资源一下被这个线程改,一下被那个线程改。
在这里插入图片描述
比如此时,还没来得及打印,刚使ticket自增,就被抢夺了执行权
在这里插入图片描述
这就引出了临界区和锁的概念,如果能在指定区域上锁,就不会出现类似的问题,但是如果锁的区域太多,就变成了顺序执行的单线程,如果锁的区域太小,无法彻底解决临界资源异常。
在这里插入图片描述
在这里插入图片描述
例如:锁对象可以是任意的类型的任意对象,但一定要是唯一的,所以使用static
在这里插入图片描述
注意,同步代码块的位置很关键,如下会导致先进入同步块的线程一个人就把任务做完了
在这里插入图片描述
注意,同一个区块需要使用同一个锁对象,一般使用当前类的字节码文件对象
在这里插入图片描述
如果要将一个方法里的所有代码都锁起来,可以直接在方法上加入Synchronized关键字
在这里插入图片描述
例如:使用Runnable来发布任务,提供ticket参数供线程对象来使用,构建同步代码块
在这里插入图片描述
例如:将买票这一行为抽象成一个方法,提取出来,加上同步修饰
此时锁对象就是Runnable对象的字节码文件,是唯一的。
在这里插入图片描述
例如:String Builder是多线程不安全的,多线程的时候应该使用String Buffer类,显然String Buffer类的方法中都是添加了同步锁的
在这里插入图片描述

Lock锁


例如:
就是在同步代码块进入区域上锁,出去的区域开锁,但要注意创建出来的锁要具有唯一性,以及一定要有开锁的余地(可以使用finally来执行开锁)
在这里插入图片描述

死锁

当不同的锁之间出现了嵌套,两边都在等着对方释放临界资源,就会产生死锁
在这里插入图片描述
例如:根据同步代码块的锁对象的不同,产生两把锁
在这里插入图片描述
在这里插入图片描述

等待唤醒机制(生产者和消费者)

经典PV操作,408必考知识点。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
例如:先创建桌子并添加锁变量
在这里插入图片描述
例如:在消费者的任务描述页面,要提示具体是哪一把锁前面有人排队,唤醒哪个锁队列中的人
在这里插入图片描述
例如:在生产者任务页面,要使用相同的锁对象来进行判断
在这里插入图片描述

通过阻塞队列实现

进入临界区时,会判断是否有数据,然后是否挂载到队列中,出临界区时看队列中有没有人,有人就提出来
在这里插入图片描述
在这里插入图片描述
例如:阻塞队列显然只能有一个,厨师的任务发布页如下,其中构造方法要求一定要传入阻塞队列
注意其中并没有锁,锁写到了队列的put方法中
在这里插入图片描述
例如:put源码
在这里插入图片描述
例如:客人的构造方法要求一定要传入阻塞队列,并且和对应的厨师保持一致,这样就能从公共队列中获取信息,其中take方法本身带锁
在这里插入图片描述
例如:take源码
在这里插入图片描述
例如:程序界面先创建共同阻塞队列对象,通过这个队列来创建厨师,需要注意的是,打印语句定义到了锁的外面,并不是临界区,所以会导致数据错误。
在这里插入图片描述

综合练习

在这里插入图片描述

package com.itheima.demo6;

public class CinemaThread extends Thread{
    public static int ticket = 1000;

    public CinemaThread(String s) {
        this.setName(s);
    }

    @Override
    public void run() {
        while (true) {
            synchronized (CinemaThread.class) {
                if (ticket > 0) {
                    try {
                        sleep(3000);
                        ticket--;
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }else {
                    break;
                }
                System.out.println(this.getName() + "卖出了一张票,还剩" + ticket + "张票");
            }
        }
    }
}
package com.itheima.demo6;

public class ThreadTest {
    public static void main(String[] args) {

        CinemaThread cinemaThread1 = new CinemaThread("窗口1");
        CinemaThread cinemaThread2 = new CinemaThread("窗口2");

        cinemaThread1.start();
        cinemaThread2.start();

    }
}

在这里插入图片描述

package com.itheima.demo6;

public class GiftSent extends Thread{
    public static int giftNum = 100;

    public GiftSent(String name) {
        this.setName(name);
    }

    @Override
    public void run() {
        while (true) {
            synchronized (GiftSent.class) {
                if (giftNum > 10) {
                    giftNum--;
                }else {
                    break;
                }
                System.out.println(this.getName() + "发出了一份礼物,还剩" + giftNum + "个");
            }
        }
    }
}
package com.itheima.demo6;

public class ThreadTest {
    public static void main(String[] args) {

        GiftSent giftSent1 = new GiftSent("A学生");
        GiftSent giftSent2 = new GiftSent("B学生");

        giftSent1.start();
        giftSent2.start();

    }
}

在这里插入图片描述

package com.itheima.demo6;

public class OddCount extends Thread{
    public static int count = 100;

    public OddCount (String name) {
        this.setName(name);
    }

    @Override
    public void run() {
        while (true){
            synchronized (OddCount.class) {
                if(count % 2 != 0) {
                    System.out.println(this.getName() + "找到了一个奇数:" + count);
                }
                if (count < 1) {
                    break;
                }else {
                    count--;
                }
            }
        }
    }
}

package com.itheima.demo6;

public class ThreadTest {
    public static void main(String[] args) {

       OddCount oddCount1 = new OddCount("A");
       OddCount oddCount2 = new OddCount("B");

       oddCount1.start();
       oddCount2.start();

    }
}

在这里插入图片描述

package com.itheima.demo6;

import java.util.Random;

public class RedBag extends Thread{
    public static int num = 3;
    public static int red = 100;

    public RedBag(String name) {
        this.setName(name);
    }

    @Override
    public void run(){
        synchronized (RedBag.class) {
            if (num > 1) {
                int t = red;
                num--;
                red -= new Random().nextInt(red);
                System.out.println(this.getName() + "抢到了" + (t - red) + "元");
            }else if (num == 1) {
                num--;
                System.out.println(this.getName() + "抢到了" + red + "元");
            }else {
                System.out.println(this.getName() + "没抢到");
            }
        }
    }
}

package com.itheima.demo6;

public class ThreadTest {
    public static void main(String[] args) {
        RedBag redBag1 = new RedBag("A");
        RedBag redBag2 = new RedBag("B");
        RedBag redBag3 = new RedBag("C");
        RedBag redBag4 = new RedBag("D");
        RedBag redBag5 = new RedBag("E");

        redBag1.start();
        redBag2.start();
        redBag3.start();
        redBag4.start();
        redBag5.start();
    }
}

在这里插入图片描述

package com.itheima.demo6;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class Bonus extends Thread{
    public static ArrayList<Integer> integerArrayList = new ArrayList<>();

    static {
        Collections.addAll(integerArrayList, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
    }

    public Bonus(String name) {
        this.setName(name);
    }

    @Override
    public void run() {
        while (true) {
            synchronized (Bonus.class) {
                if(integerArrayList.isEmpty()) {
                    break;
                }else {
                    int t = new Random().nextInt(integerArrayList.size());
                    System.out.println(this.getName() + "抽到了" + integerArrayList.get(t) + "元");
                    integerArrayList.remove(t);
                }
            }
        }
    }
}

package com.itheima.demo6;

public class ThreadTest {
    public static void main(String[] args) {
        Bonus bonus1 = new Bonus("抽奖箱1");
        Bonus bonus2 = new Bonus("抽奖箱2");

        bonus1.start();
        bonus2.start();
    }
}

package com.itheima.demo6;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class Bonus extends Thread{
    public static ArrayList<Integer> integerArrayList = new ArrayList<>();
    private ArrayList<Integer> integerArrayList1 = new ArrayList<>();

    static {
        Collections.addAll(integerArrayList, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
    }

    public Bonus(String name) {
        this.setName(name);

    }

    @Override
    public void run() {
        while (true) {
            synchronized (Bonus.class) {
                if(integerArrayList.isEmpty()) {
                    System.out.print(this.getName() + "抽到了" + integerArrayList1.size() + "个奖,分别为:");
                    String str = "";
                    int num = 0;
                    int max = 0;
                    for (Integer i : integerArrayList1) {
                        str += i + ",";
                        num += i;
                        max = max<=i?i:max;
                    }
                    str = str.subSequence(0, str.length() - 1).toString();
                    System.out.println(str + " 最高" + max +"元" + ",共计" + num + "元");
                    break;
                }else {
                    int t = new Random().nextInt(integerArrayList.size());
                    this.integerArrayList1.add(integerArrayList.get(t));
                    integerArrayList.remove(t);
                }
            }
        }
    }


}

package com.itheima.demo6;

public class ThreadTest {
    public static void main(String[] args) {

        Bonus bonus1 = new Bonus("抽奖箱1");
        Bonus bonus2 = new Bonus("抽奖箱2");

        bonus1.start();
        bonus2.start();

    }
}

在这里插入图片描述

package com.itheima.demo6;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class Bonus extends Thread{
    public static ArrayList<Integer> integerArrayList = new ArrayList<>();
    private ArrayList<Integer> integerArrayList1 = new ArrayList<>();
    private static int join_num = 2;
    private static boolean flag = true;
    private static int maxBonus = 0;
    private static String name1 = "";
    

    static {
        Collections.addAll(integerArrayList, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
    }

    public Bonus(String name) {
        this.setName(name);
    }

    @Override
    public void run() {
        while (true) {
            synchronized (Bonus.class) {
                if(integerArrayList.isEmpty()) {
                    System.out.print(this.getName() + "抽到了" + integerArrayList1.size() + "个奖,分别为:");
                    String str = "";
                    int num = 0;
                    int max = 0;
                    for (Integer i : integerArrayList1) {
                        str += i + ",";
                        num += i;
                        max = max<=i?i:max;
                    }
                    str = str.subSequence(0, str.length() - 1).toString();
                    System.out.println(str + " 最高" + max +"元" + ",共计" + num + "元");
                    if(maxBonus <= max) {
                        maxBonus = max;
                        name1 = this.getName();
                    }
                    break;
                }else {
                    int t = new Random().nextInt(integerArrayList.size());
                    this.integerArrayList1.add(integerArrayList.get(t));
                    integerArrayList.remove(t);
                }
            }
        }
        join_num--;
        while (join_num > 0){
            try {
                sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e)
            }
        }
        synchronized (Bonus.class) {
            if (flag) {
                System.out.println("最高奖" + maxBonus + "元,由" + name1 + "取得");
                flag = !flag;
            }
        }
    }
}

package com.itheima.demo6;

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        
        Bonus bonus1 = new Bonus("抽奖箱1");
        Bonus bonus2 = new Bonus("抽奖箱2");

        bonus1.start();
        bonus2.start();

    }
}

使用第三种有返回值的方法

package com.itheima.demo6;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.Callable;

public class Bonus implements Callable {
    public static ArrayList<Integer> integerArrayList = new ArrayList<>();
    private int max = 0;

    static {
        Collections.addAll(integerArrayList, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
    }

    @Override
    public Integer call() throws Exception {
        ArrayList<Integer> integerArrayList1 = new ArrayList<>();
        String name = Thread.currentThread().getName();
        while (true) {
            synchronized (Bonus.class) {
                if(integerArrayList.isEmpty()) {
                    System.out.print(name + "抽到了" + integerArrayList1.size() + "个奖,分别为:");
                    String str = "";
                    int num = 0;
                    for (Integer i : integerArrayList1) {
                        str += i + ",";
                        num += i;
                        max = max<=i?i:max;
                    }
                    str = str.subSequence(0, str.length() - 1).toString();
                    System.out.println(str + " 最高" + max +"元" + ",共计" + num + "元");
                    break;
                }else {
                    int t = new Random().nextInt(integerArrayList.size());
                    integerArrayList1.add(integerArrayList.get(t));
                    integerArrayList.remove(t);
                }
            }
        }
        return max;
    }
}

package com.itheima.demo6;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException {


        Bonus bonus = new Bonus();

        FutureTask<Integer> futureTask1 = new FutureTask<>(bonus);
        FutureTask<Integer> futureTask2 = new FutureTask<>(bonus);

        Thread bonus1 = new Thread(futureTask1);
        Thread bonus2 = new Thread(futureTask2);

        bonus1.setName("抽奖箱1");
        bonus2.setName("抽奖箱2");

        bonus1.start();
        bonus2.start();

       Integer num1 = futureTask1.get();
       Integer num2 = futureTask2.get();

       if(num1 > num2) {
           System.out.println("抽奖箱1抽到了最大奖" + num1 + "元");
       }else {
           System.out.println("抽奖箱2抽到了最大奖" + num2 + "元");
       }

    }
}

线程池

以前通过多线程完成任务的时候,使用完线程就消亡了,每次创建进程都要重新分配资源,浪费很多时间
在这里插入图片描述
设置一个线程池,保存可以用来进行任务的线程(工人)
在这里插入图片描述
在这里插入图片描述
线程池可以理解成特殊的线程集合,任务可以直接发布给这个线程集合。(相当于一个工会)
每次给线程池提交一个任务都会发起一个新的线程来做事。
例如:无上限线程池
在这里插入图片描述
例如:有上限线程池,指只有三个线程做事
在这里插入图片描述
但是这个工具类不够灵活,每次都要手动排队
在这里插入图片描述

在这里插入图片描述
当阻塞队伍排满了,核心线程都在忙,才会创建临时线程
在这里插入图片描述
如果任务总数超过了核心数、临时数、队伍长度之和,就会触发任务拒绝策略
在这里插入图片描述
在这里插入图片描述
例如:创建参数详细的线程池
在这里插入图片描述
在这里插入图片描述
一般使用工具来测试
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2073217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信服务号网页授权域名配置数不够方案验证

文章目录 问题说明方案验证涉及工具结论 问题说明 微信服务号网页授权域名只能配置两个&#xff0c;而又没法直接配置主域名的形式&#xff0c;目前只能选取其中的一个业务域名来进行统一跳转解决。 方案验证 服务号现有配置数量限制如下&#xff1a; 申请测试号验证&#…

数据仓库系列 5:什么是事实表和维度表,它们有什么作用?

目录 1. 引言&#xff1a;事实表与维度表的魔力2. 事实表&#xff1a;业务活动的数字足迹2.1 什么是事实表?2.2 事实表的特征2.3 事实表的类型2.4 事实表示例2.5 事实表的作用2.6 事实表的设计原则2.7 事实表的查询示例 3. 维度表&#xff1a;为数据赋予意义3.1 什么是维度表?…

Mysql语句性能优化

SQL查询过程 查询缓存&#xff1a; 执行查询语句的时候&#xff0c;会先查询缓存&#xff08;MySQL 8.0 版本后移除&#xff0c;因为这个功能不太实用&#xff09;。分析器&#xff1a; 没有命中缓存的话&#xff0c;SQL 语句就会经过分析器&#xff0c;分析器说白了就是要先看…

logistic方程求解和模拟

logistic规律可以用以下式子表示 N(t1)​k*N(t)*​(N-N(t)) 其中N(t)为t时刻种群的数量&#xff0c;N为环境最大容纳的的种群数 k的取值通常与N有关&#xff0c;大约在1/N和4/N之间 题目如下 假设一些参数后的代码如下 T100; T11:T; N11000; a13/N1; Q800; N2700; a2-0.2/…

洛谷 P10119 『STA - R4』踱步

题目来源于&#xff1a;洛谷 题目本质&#xff1a;动态规划及优化&#xff0c;单调队列 题目思路&#xff1a; 设 fi,k,op​ 表示对于前 i 个位置&#xff0c;强制在 i1 分钟初踱步&#xff0c;总共踱步 k 次&#xff0c;且第 i 分钟在屋内&#xff08;op0&#xff09;或屋外…

leetcode73. 矩阵置零,简单模拟

leetcode73. 矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 示…

Stable Diffusion之提示词指南(二)

在上一篇的文章中&#xff0c;我们讲解了Stable Diffusion提示词的基本用法&#xff0c;不了解的到可以去学习一下———Stable Diffusion之提示词指南(一)。这章我们再详细讲解一下其他高级用法和负提示词。 注意&#xff1a;部分语法只是适用于AUTOMATIC1111 Web UI(以下简称…

SpringBoot集成kafka-指定topic(主题)-partition(分区)-offset(偏移量)消费信息

SpringBoot集成kafka-指定topic-partition-offset消费信息 1、消费者2、生产者3、配置类4、配置文件5、实体类6、工具类7、测试类8、第一次测试&#xff08;读取到19条信息&#xff09;9、第二次测试&#xff08;读取到3条信息&#xff09; 1、消费者 指定消费者读取配置文件中…

[pytorch] --- pytorch环境配置

本教程环境搭建基于windows 1 安装miniconda 1.1 miniconda与anaconda的区别 包含的包: Anaconda: 是一个较大的发行版&#xff0c;预装了大量的科学计算和数据分析相关的 Python 包。Miniconda: 更轻量级&#xff0c;只包含 Conda、Python 和它们的依赖&#xff0c;以及少…

微信小程序获取用户openId并通过服务端向用户发送模板消息

1.引言 注意&#xff1a; 1.标题中的服务端是自己研发的服务端&#xff0c;不是腾讯公司的服务端。 2.小程序的模板消息分为一次性订阅消息与长期订阅&#xff0c;一次性订阅就是每次在给用户发送消息之前都需要获得用户的同意&#xff08;即用户订阅&#xff09;&#xff0…

数据结构(树、平衡树、红黑树)

目录 树 树的遍历方式 平衡二叉树 旋转机制 左旋 右旋 旋转实例 左左 左右 右右 右左 总结 红黑树 树 相关概念 节点的内部结构如下 二叉树与二叉搜索树的定义 树的遍历方式 前序遍历&#xff1a;当前节点&#xff0c;左子节点&#xff0c;右子结点 中序遍历&a…

React学习day01-React-开发环境配置、JSX基础-本质、JSX中js表达式的用法、JSX的条件渲染

1、React &#xff08;1&#xff09;概念&#xff1a;由Meta公司研发&#xff0c;是一个用于构建Web和原生交互页面的库 &#xff08;2&#xff09;优点&#xff1a; 1&#xff09;相较于传统基于DOM开发的优势&#xff1a;组件化的开发方式、不错的性能 2&#xff09;相较于…

软件设计原则之单一职责原则

目录 单一职责原则单一职责原则的主要特点应用范围Demo用户信息日志记录 单一职责原则 单一职责原则&#xff08;Single Responsibility Principle&#xff0c;简称SRP&#xff09;是面向对象设计中的一个重要原则&#xff0c;其核心思想是&#xff1a;一个类应该仅有一个引起…

ollma 本地部署大模型

因为我本地是 windows 的系统&#xff0c;所以这里直接写的是通过 docker 来实现本地大模型的部署。 windows 下 WSl 的安装这里就不做重复&#xff0c;详见 windows 部署 mindspore GPU 开发环境&#xff08;WSL&#xff09; 一、Docker 部署 ollma 1. 拉取镜像&#xff08;…

Ubuntu系统设置Java项目开机自启

1、创建自启动脚 sudo vi /etc/systemd/system/java-service.service 2、编辑自启脚本 [Unit]部分包含了service的描述和依赖关系。在这个示例中&#xff0c;我们将其设置为在系统启动后执行。 [Service]部分定义了service的执行方式。在这个示例中&#xff0c;我们指定了Java…

shell工具箱集合!!

shell工具箱集合 1.shell工具箱集合 2.Chrony 时间同步 3.Get_host_Info 设备信息收集 4.Init_host 系统初始化 5.Iperf 带宽测试套件 6.Lagscope_test 时延测试套件 7.Mtr_test 双向路由探测套件 下载地址&#xff1a; https://pan.quark.cn/s/6936cc13bc04

学习笔记——Redis基础

文章目录 Redis五种常用数据类型Redis常用命令Spring Data Redis使用方式操作步骤 Redis五种常用数据类型 Redis存储的是key-values结构的数据&#xff0c;其中key是字符串类型&#xff0c;value有五种常用的数据类型&#xff1a; 字符串&#xff08;string&#xff09;&…

C++入门基础知识32——【关于C++ 存储类之auto存储类】

成长路上不孤单&#x1f60a;【14后&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff01;&#xff01;&#xff01;&#xff01;&#xff…

Flex的基本使用+综合案例

组成 弹性盒子没有设置高&#xff0c;就会自动拉伸 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&q…

高并发下阻塞队列的选择

高并发下阻塞队列的选择 一、队列 队列&#xff1a;queue。简称队&#xff0c;它和堆栈一样&#xff0c;也是一种运算受限的线性表&#xff0c;其限制是仅允许在表的一端进行插入&#xff0c;而在表的另一端进行删除。 简单的说&#xff0c;采用该结构的集合&#xff0c;对元素…