2-Java进阶知识总结-6-多线程

news2024/9/23 1:22:17

文章目录

  • 多线程--基本概念
    • 并发和并行
    • 进程和线程
    • 多线程
  • 多线程--实现
    • 方式一,继承Thread类
      • 方法介绍
      • 实现步骤
      • 注意事项
    • 方式二,实现Runnable接口
      • Thread构造方法
      • 实现步骤
    • 方式三,实现Callable接口
      • 方法介绍
      • 实现步骤
    • 三种多线程实现方法对比
  • 多线程--线程方法
    • 设置和获取线程名称
    • 线程休眠
    • 线程优先级
    • 守护线程
    • 礼让线程和插入线程
    • 线程生命周期
  • 多线程--线程同步
    • 示例:卖票
    • 问题发现
    • 问题解决1:同步代码块
    • 问题解决2:同步方法
    • 问题解决3:线程锁Lock
  • 多线程应用--死锁【非概念,是一种BUG现象】
  • 多线程应用--生产者消费者模式示例
    • 等待唤醒机制
    • 阻塞队列实现等待唤醒机制
  • 多线程的6种状态
  • 线程池

多线程–基本概念

并发和并行

  • 并行:在同一时刻,有多个指令在多个CPU上同时执行

  • 并发:在同一时刻,有多个指令在单个CPU上交替执行

进程和线程

进程:是正在运行的程序

  • 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位
  • 动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的
  • 并发性:任何进程都可以同其他进程一起并发执行

线程:是进程中的单个顺序控制流,是一条执行路径

  • 单线程:一个进程如果只有一条执行路径,则称为单线程程序

  • 多线程:一个进程如果有多条执行路径,则称为多线程程序

image-20231023165600023

  • 360安全卫士是一个进程;QQ是另外一个进程
  • 木马查杀、电脑清理、系统修复是不同的线程

多线程

指从软件或者硬件上实现多个线程并发执行的技术

  • 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能

多线程–实现

方式一,继承Thread类

方法介绍

方法名说明
void run()在线程开启后,此方法将被调用执行
void start()使此线程开始执行,Java虚拟机会调用run方法()

实现步骤

  • 定义一个类MyThread继承Thread类
  • 在MyThread类中重写run()方法
  • 创建MyThread类的对象
  • 启动线程
public class MyThread extends Thread {
    @Override
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println(i);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args) {
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

//        my1.run();
//        my2.run();

        //void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法
        my1.start();
        my2.start();
    }
}

注意事项

为什么要重写run()方法?

  • 因为run()是用来封装被线程执行的代码

run()方法和start()方法的区别?

  • run():封装线程执行的代码,直接调用,相当于普通方法的调用

  • start():启动线程;然后由JVM调用此线程的run()方法

方式二,实现Runnable接口

Thread构造方法

方法名说明
Thread(Runnable target)分配一个新的Thread对象
Thread(Runnable target, String name)分配一个新的Thread对象

实现步骤

  • 定义一个类MyRunnable实现Runnable接口
  • 在MyRunnable类中重写run()方法
  • 创建MyRunnable类的对象
  • 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
  • 启动线程
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class MyRunnableDemo {
    public static void main(String[] args) {
        //创建MyRunnable类的对象
        MyRunnable my = new MyRunnable();

        //创建Thread类的对象,把MyRunnable对象作为构造方法的参数
		
        // Thread(Runnable target)
        Thread t1 = new Thread(my);
        Thread t2 = new Thread(my);
        
        //Thread(Runnable target, String name)
        Thread t1 = new Thread(my,"坦克");
        Thread t2 = new Thread(my,"飞机");

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

方式三,实现Callable接口

方法介绍

方法名说明
V call()计算结果,如果无法计算结果,则抛出一个异常
FutureTask(Callable callable)创建一个 FutureTask,一旦运行就执行给定的 Callable
V get()如有必要,等待计算完成,然后获取其结果

实现步骤

  • 定义一个类MyCallable实现Callable接口
  • 在MyCallable类中重写call()方法
  • 创建MyCallable类的对象
  • 创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
  • 创建Thread类的对象,把FutureTask对象作为构造方法的参数
  • 启动线程
  • 再调用get方法,就可以获取线程结束之后的结果。
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println("跟女孩表白" + i);
        }
        //返回值就表示线程运行完毕之后的结果
        return "答应";
    }
}

public class Demo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //线程开启之后需要执行里面的call方法
        MyCallable mc = new MyCallable();

        //可以获取线程执行完毕之后的结果.也可以作为参数传递给Thread对象
        FutureTask<String> ft = new FutureTask<>(mc);

        //创建线程对象
        Thread t1 = new Thread(ft);

        String s = ft.get();
        //开启线程
        t1.start();

        //String s = ft.get();
        System.out.println(s);
    }
}

三种多线程实现方法对比

优点缺点
实现Runnable、Callable接口扩展性强,实现该接口的同时还可以继承其他的类编程相对复杂,不能直接使用Thread类中的方法
继承Thread类编程比较简单,可以直接使用Thread类中的方法可扩展性较差,不能再继承其他的类

多线程–线程方法

设置和获取线程名称

方法名说明
void setName(String name)将此线程的名称更改为等于参数name
String getName()返回此线程的名称
Thread currentThread()返回对当前正在执行的线程对象的引用
public class MyThread extends Thread {
    public MyThread() {}
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+":"+i);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args) {
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        //void setName(String name):将此线程的名称更改为等于参数 name
        my1.setName("高铁");
        my2.setName("飞机");

        //Thread(String name)
        MyThread my1 = new MyThread("高铁");
        MyThread my2 = new MyThread("飞机");

        my1.start();
        my2.start();

        //static Thread currentThread() 返回对当前正在执行的线程对象的引用
        System.out.println(Thread.currentThread().getName());
    }
}

线程休眠

方法名说明
static void sleep(long millis)使当前正在执行的线程停留(暂停执行)指定的毫秒数
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
    }
}
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        /*System.out.println("睡觉前");
        Thread.sleep(3000);
        System.out.println("睡醒了");*/

        MyRunnable mr = new MyRunnable();

        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);

        t1.start();
        t2.start();
    }
}

线程优先级

线程调度方式

  • 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
  • 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些
    • 随机性

Java使用的是抢占式调度模型

优先级相关方法

方法名说明
final int getPriority()返回此线程的优先级
final void setPriority(int newPriority)更改此线程的优先级线程默认优先级是5;线程优先级的范围是:1-10
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
        return "线程执行完毕了";
    }
}
public class Demo {
    public static void main(String[] args) {
        //优先级: 1 - 10 默认值:5
        MyCallable mc = new MyCallable();

        FutureTask<String> ft = new FutureTask<>(mc);

        Thread t1 = new Thread(ft);
        t1.setName("飞机");
        t1.setPriority(10);
        //System.out.println(t1.getPriority());//5
        t1.start();

        MyCallable mc2 = new MyCallable();

        FutureTask<String> ft2 = new FutureTask<>(mc2);

        Thread t2 = new Thread(ft2);
        t2.setName("坦克");
        t2.setPriority(1);
        //System.out.println(t2.getPriority());//5
        t2.start();
    }
}

守护线程

当非守护线程结束之后,守护线程也会相继结束

方法名说明
void setDaemon(boolean on)将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
public class MyThread1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + "---" + i);
        }
    }
}
public class MyThread2 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + "---" + i);
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();

        t1.setName("女神");
        t2.setName("备胎");

        //把第二个线程设置为守护线程
        //当普通线程执行完之后,那么守护线程也没有继续运行下去的必要了.
        t2.setDaemon(true);

        t1.start();
        t2.start();
    }
}

礼让线程和插入线程

方法名说明
public static void yield()出让线程,当前线程让出cpu
public static void join()插入线程,把一个线程插入到当前线程前面,该线程执行完毕,才会执行当前线程后面的代码
package com.itheima.a07threadmethod4;

public class MyThread extends Thread{

    @Override
    public void run() {//"飞机"  "坦克"
        for (int i = 1; i <= 100; i++) {

            System.out.println(getName() + "@" + i);
            //表示出让当前CPU的执行权
            Thread.yield();
        }
    }
}
package com.itheima.a08threadmethod5;

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {

        MyThread t = new MyThread();
        t.setName("土豆");
        t.start();

        //表示把t这个线程,插入到当前线程之前。
        //t:土豆
        //当前线程: main线程
        t.join();

        //执行在main线程当中的
        for (int i = 0; i < 10; i++) {
            System.out.println("main线程" + i);
        }
    }
}

线程生命周期

image-20231023184503271

多线程–线程同步

示例:卖票

案例需求

  • 某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票

实现步骤

  • 定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:private int tickets = 100;

  • 在SellTicket类中重写run()方法实现卖票,代码步骤如下

  • 判断票数大于0,就卖票,并告知是哪个窗口卖的

  • 卖了票之后,总票数要减1

  • 票卖没了,线程停止

  • 定义一个测试类SellTicketDemo,里面有main方法,代码步骤如下

  • 创建SellTicket类的对象

  • 创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称

  • 启动线程

public class SellTicket implements Runnable {
    private int tickets = 100;
    //在SellTicket类中重写run()方法实现卖票,代码步骤如下
    @Override
    public void run() {
        while (true) {
            if(ticket <= 0){
                    //卖完了
                    break;
                }else{
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
                }
        }
    }
}

public class SellTicketDemo {
    public static void main(String[] args) {
        //创建SellTicket类的对象
        SellTicket st = new SellTicket();

        //创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称
        Thread t1 = new Thread(st,"窗口1");
        Thread t2 = new Thread(st,"窗口2");
        Thread t3 = new Thread(st,"窗口3");

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

问题发现

卖票出现了问题

  • 相同的票出现了多次

  • 出现了负数的票

问题产生原因

  • 线程执行的随机性导致的,可能在卖票过程中丢失cpu的执行权,导致出现问题

安全问题出现的条件

  • 是多线程环境

  • 有共享数据

  • 有多条语句操作共享数据

如何解决多线程安全问题呢?

  • 基本思想:让程序没有安全问题的环境

怎么实现呢?

  • 把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可

  • Java提供了同步代码块的方式来解决

问题解决1:同步代码块

synchronized(任意对象) { 
	多条语句操作共享数据的代码 
}

同步的好处和弊端

  • 好处:解决了多线程的数据安全问题

  • 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

public class SellTicket implements Runnable {
    private int tickets = 100;
    private Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) { // 对可能有安全问题的代码加锁,多个线程必须使用同一把锁
                //t1进来后,就会把这段代码给锁起来
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                        //t1休息100毫秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //窗口1正在出售第100张票
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                    tickets--; //tickets = 99;
                }
            }
            //t1出来了,这段代码的锁就被释放了
        }
    }
}

public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket st = new SellTicket();

        Thread t1 = new Thread(st, "窗口1");
        Thread t2 = new Thread(st, "窗口2");
        Thread t3 = new Thread(st, "窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

问题解决2:同步方法

非静态同步方法

修饰符 synchronized 返回值类型 方法名(方法参数) { 
	方法体;
}
  • 锁对象:this

静态同步方法

修饰符 static synchronized 返回值类型 方法名(方法参数) { 
	方法体;
}
  • 锁对象:类名.class
public class MyRunnable implements Runnable {
    private static int ticketCount = 100;

    @Override
    public void run() {
        while(true){
            if("窗口一".equals(Thread.currentThread().getName())){
                //同步方法
                boolean result = synchronizedMthod();
                if(result){
                    break;
                }
            }

            if("窗口二".equals(Thread.currentThread().getName())){
                //同步代码块
                synchronized (MyRunnable.class){
                    if(ticketCount == 0){
                       break;
                    }else{
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        ticketCount--;
                        System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticketCount + "张票");
                    }
                }
            }

        }
    }

    private static synchronized boolean synchronizedMthod() {
        if(ticketCount == 0){
            return true;
        }else{
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticketCount--;
            System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticketCount + "张票");
            return false;
        }
    }
}

问题解决3:线程锁Lock

方法名说明
ReentrantLock()创建一个ReentrantLock的实例
  • Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
方法名说明
void lock()获得锁
void unlock()释放锁
public class Ticket implements Runnable {
      //票的数量
      private int ticket = 100;
      private Object obj = new Object();
      private ReentrantLock lock = new ReentrantLock();  // 定义为静态变量

      @Override
      public void run() {
          while (true) {
              //synchronized (obj){//多个线程必须使用同一把锁.
              try {
                  lock.lock();
                  if (ticket <= 0) {
                      //卖完了
                      break;
                  } else {
                      Thread.sleep(100);
                      ticket--;
                      System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
                  }
              } catch (InterruptedException e) {
                  e.printStackTrace();
              } finally {
                  lock.unlock();
              }
              // }
          }
      }
  }


public class Demo {
  public static void main(String[] args) {
      Ticket ticket = new Ticket();

      Thread t1 = new Thread(ticket);
      Thread t2 = new Thread(ticket);
      Thread t3 = new Thread(ticket);

      t1.setName("窗口一");
      t2.setName("窗口二");
      t3.setName("窗口三");

      t1.start();
      t2.start();
      t3.start();
  }
}

多线程应用–死锁【非概念,是一种BUG现象】

线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行

什么情况下会产生死锁?

  • 资源有限

  • 同步嵌套

package com.itheima.a12deadlock;


public class ThreadDemo {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("线程A");
        t2.setName("线程B");

        t1.start();
        t2.start();

    }
}


package com.itheima.a12deadlock;

public class MyThread extends Thread {

    static Object objA = new Object();
    static Object objB = new Object();

    @Override
    public void run() {
        //1.循环
        while (true) {
            if ("线程A".equals(getName())) {
                synchronized (objA) {
                    System.out.println("线程A拿到了A锁,准备拿B锁");//A
                    synchronized (objB) {
                        System.out.println("线程A拿到了B锁,顺利执行完一轮");
                    }
                }
            } else if ("线程B".equals(getName())) {
                if ("线程B".equals(getName())) {
                    synchronized (objB) {
                        System.out.println("线程B拿到了B锁,准备拿A锁");//B
                        synchronized (objA) {
                            System.out.println("线程B拿到了A锁,顺利执行完一轮");
                        }
                    }
                }
            }
        }
    }
}

多线程应用–生产者消费者模式示例

等待唤醒机制

阻塞队列实现等待唤醒机制

多线程的6种状态

没有运行状态

  • 运行状态只是方便理解

image-20231023195203688

线程状态具体含义
新建状态 NEW一个尚未启动的线程的状态。也称之为初始状态、开始状态。线程刚被创建,但是并未启动。还没调用start方法。MyThread t = new MyThread()只有线程象,没有线程特征。
就绪状态 RUNNABLE当我们调用线程对象的start方法,那么此时线程对象进入了RUNNABLE状态。那么此时才是真正的在JVM进程中创建了一个线程,线程一经启动并不是立即得到执行,线程的运行与否要听令与CPU的调度,那么我们把这个中间状态称之为可执行状态(RUNNABLE)也就是说它具备执行的资格,但是并没有真正的执行起来而是在等待CPU的度。
阻塞状态 BLOCKED当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态
等待状态 WAITING一个正在等待的线程的状态。也称之为等待状态。造成线程等待的原因有两种,分别是调用Object.wait()、join()方法。处于等待状态的线程,正在等待其他线程去执行一个特定的操作。例如:因为wait()而等待的线程正在等待另一个线程去调用notify()或notifyAll();一个因为join()而等待的线程正在等待另一个线程结束。
计时状态 TIMED_WAITING一个在限定时间内等待的线程的状态。也称之为限时等待状态。造成线程限时等待状态的原因有三种,分别是:Thread.sleep(long),Object.wait(long)、join(long)。
结束状态 TERMINATED一个完全运行完成的线程的状态。也称之为终止状态、结束状态

线程池

暂空

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

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

相关文章

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程

导学了解 什么是进程&#xff1f; 进程&#xff1a;程序的基本执行实体 更加通俗的讲&#xff1a;一个软件执行后&#xff0c;它就是一个进程&#xff0c;绿色的内容都是一个进程。 什么是线程&#xff1f; 线程是操作系统能够进行运算调度的最小单位。它被包含在进程当中&…

【蓝桥】小蓝的疑问

1、题目 问题描述 小蓝和小桥上完课后&#xff0c;小桥回顾了课上教的树形数据结构&#xff0c;他在地上画了一棵根节点为 1 的树&#xff0c;并且对每个节点都赋上了一个权值 w i w_i wi​。 小蓝对小桥多次询问&#xff0c;每次询问包含两个整数 x , k x,k x,k&#xff…

Iterator迭代器

一、基本概念 Iterator迭代器是一种接口&#xff0c;为不同的数据结构提供一种访问机制&#xff0c;即for … of 循环。当使用for…of循环遍历某种数据结构时&#xff0c;该循环会自动去寻找 Iterator 接口。任何数据结构只要部署Iterator接口&#xff0c;就可以完成遍历操作(…

基于Pytorch的驾驶员分心行为实时检测

本文使用深度学习和Pytorch(PyTorch 2.0.1\Torchvision 0.15.2)实时检测驾驶员的分心行为,并附录完整代码。 检测分心驾驶是现代汽车中最重要的功能之一。无论是自动驾驶汽车还是其它高端汽车,都配备了驾驶员监控系统,以持续跟踪驾驶员的行为。这对确保驾驶员保持目光在道路…

Unity的碰撞检测(二)

温馨提示&#xff1a;本文基于前一篇“Unity的碰撞检测(一)”继续探讨Collider输出&#xff0c;阅读本文则默认已阅读前文。 &#xff08;一&#xff09;测试说明 对于Collider输出&#xff0c;我们首先应该保证两个游戏对象具备的是碰撞器而非触发器&#xff0c;所以碰撞器的…

LSTM算法精解(附案例代码)

概念 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种循环神经网络&#xff08;RNN&#xff09;的变种&#xff0c;用于处理序列数据&#xff0c;特别是在需要长期依赖关系的情况下。LSTM旨在解决传统RNN存在的梯度消失和梯度爆炸问题&#xff0c;这些问题使得RNN难…

18 Transformer 的动态流程

博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from333.1007.0.0 b 站直接看 配套 github 链接&#xff1a;https://github.com/nickchen121/Pre-training-language-model 配套博客链接&#xff1a;https://www.cnblogs.com/nickchen121/p/15105048.html 机…

【BI看板】superset api接口分析

superset 的图表功能已经非常强大了&#xff0c;但是要满足个性化需求&#xff0c;定制是比不可少的了。。。来吧&#xff0c;我们一起看看他的API。 自带api文档 URL 127.0.0.1:5000/swagger/v1 截图 是不是很熟悉&#xff0c;没错就是swagger了。 图表接口地址 127.0.0.1:…

2698 求一个整数的惩罚数 (子集和,DFS)

class Solution { public:bool dfs(int target, string s, int index, int sum) {// 只有整个字符串都被分割&#xff0c;求和&#xff0c;和看结果是不是等于targetif(index s.size()) {return sum target;}int num 0; // 在现在的子集中去依次加入余下的元素// 1 2 9 6// …

vue3 code format bug

vue code format bug vue客户端代码格式化缺陷&#xff0c;为了方便阅读和维护&#xff0c;对代码格式化发现这个缺陷 vue.global.min.3.2.26.js var Vuefunction(r){"use strict";function e(e,t){const nObject.create(null);var re.split(",");for(le…

VLAN实现二层流量隔离(mux-vlan)应用基础配置

MUX VLAN能够提供VLAN内的二层流量隔离机制。 MUX VLAN的类型如下所示 主VLAN: 加入主VLAN的接口可以和MUX VLAN内的所有接口进行通信 从VLAN: (1)隔离型从VLAN: 同一VLAN内接口之间不能互相通信&#xff0c;可以与主VLAN接口通信&#xff0c;不同从VLAN之间不能互相通信。 …

Xcode iOS app启用文件共享

在info.plist中添加如下两个配置 Supports opening documents in place Application supports iTunes file sharing 结果都为YES&#xff0c;如下图所示&#xff1a; 然后&#xff0c;iOS设备查看&#xff0c;文件->我的iPhone列表中有一个和你工程名相同的文件夹出现&…

MySQL——MySQL常见的面试知识

1、事务四大特性 原子性&#xff1a; 根据定义&#xff0c;原子性是指一个事务是一个不可分割的工作单位&#xff0c;其中的操作要么都做&#xff0c;要么都不做。即要么转账成功&#xff0c;要么转账失败&#xff0c;是不存在中间的状态&#xff01;MySQL的InnoDB引擎是靠 un…

Mysql数据库 4.SQL语言 DQL数据操纵语言 查询

DQL数据查询语言 从数据表中提取满足特定条件的记录 1.单表查询 2.多表查询 查询基础语法 select 关键字后指定要查询到的记录的哪些列 语法&#xff1a;select 列名&#xff08;字段名&#xff09;/某几列/全部列 from 表名 [具体条件]&#xff1b; select colnumName…

UI设计公司成长日记2:修身及持之以恒不断学习是要务

作者&#xff1a;蓝蓝设计 要做一个好的UI设计公司,不仅要在能力上设计能力一直&#xff08;十几年几十年&#xff09;保持优秀稳定的保持输出&#xff0c;以及心态的平和宽广。创始人对做公司要有信心&#xff0c;合伙人之间要同甘共苦&#xff0c;遵守规则&#xff0c;做好表…

text-indent 的特殊性

目录 前言 1. text-indent 的基本用法 代码示例 理解 2. text-indent 的特殊性质 2.1 负值 代码示例 理解 2.2 与其他文本属性的交互 代码示例 理解 2.3 在不同元素上的表现 代码示例 理解 3. 如何正确使用 text-indent 前言 text-indent 是 CSS 中一个用来控制…

1401 位置编码公式详细理解补充

博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https://github.com/nickchen121/Pre-training-language-model 配套博客链接:https://www.cnblogs.com/nickchen121/p/15105048.html Self-Attention:对于每…

day01:数据库DDL

一:基础概念 数据库:存储数据的仓库&#xff0c;数据是有组织的进行存储 数据库管理系统:操纵和管理数据库的大型软件 SQL&#xff1a;操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准 关系图 二:数据模型 关系型数据库:建…

LSM树原理详解

LSM树(Log-Structured-Merge-Tree)的名字往往会给初识者一个错误的印象&#xff0c;事实上&#xff0c;LSM树并不像B树、红黑树一样是一颗严格的树状数据结构&#xff0c;它其实是一种存储结构&#xff0c;目前HBase,LevelDB,RocksDB这些NoSQL存储都是采用的LSM树。 LSM树的核…

基于Java的智能仓库(进销存)管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…