当前位置: 首页 > news >正文

【JavaEE初阶】线程 和 thread

本节⽬标
  • 认识多线程
  • 掌握多线程程序的编写
  • 掌握多线程的状态

一. 认识线程(Thread)

1概念

1) 线程是什么

       

         ⼀个线程就是⼀个 "执⾏流". 每个线程之间都可以按照顺序执⾏⾃⼰的代码. 多个线程之间 "同时" 执⾏着多份代码.

        还是回到我们之前的银⾏的例⼦中。之前我们主要描述的是个⼈业务,即⼀个⼈完全处理⾃⼰的业务。我们进⼀步设想如下场景:

        ⼀家公司要去银⾏办理业务,既要进⾏财务转账,⼜要进⾏福利发放,还得进⾏缴社保。
        如果只有张三⼀个会计就会忙不过来,耗费的时间特别⻓。为了让业务更快的办理好,张三⼜找来两位同事李四、王五⼀起来帮助他,三个⼈分别负责⼀个事情,分别申请⼀个号码进⾏排队,⾃此就有了三个执⾏流共同完成任务,但本质上他们都是为了办理⼀家公司的业务。
        此时,我们就把这种情况称为多线程,将⼀个⼤任务分解成不同⼩任务,交给不同执⾏流就分别排队 执⾏。其中李四、王五都是张三叫来的,所以张三⼀般被称为主线程(Main Thread)。

2) 为啥要有线程

⾸先, "并发编程" 成为 "刚需".

  • 单核 CPU 的发展遇到了瓶颈. 要想提⾼算⼒, 就需要多核 CPU. ⽽并发编程能更充分利⽤多核 CPU资源.
  • 有些任务场景需要 "等待 IO", 为了让等待 IO 的时间能够去做⼀些其他的⼯作, 也需要⽤到并发编程.

其次, 虽然多进程也能实现 并发编程, 但是线程⽐进程更轻量.(线程就是轻量级进程)

  • 创建线程⽐创建进程更快.
  • 销毁线程⽐销毁进程更快.
  • 调度线程⽐调度进程更快.

最后, 线程虽然⽐进程轻量, 但是⼈们还不满⾜, 于是⼜有了 "线程池"(ThreadPool) 和 "协程"(Coroutine)

3) 进程和线程的区别

  • 进程是包含线程的. 每个进程⾄少有⼀个线程存在,即主线程。
  • 进程和进程之间不共享内存空间. 同⼀个进程的线程之间共享同⼀个内存空间.
⽐如之前的多进程例⼦中,每个客⼾来银⾏办理各⾃的业务,但他们之间的票据肯定是不想让别⼈知道的,否则钱不就被其他⼈取⾛了么。⽽上⾯我们的公司业务中,张三、李四、王五虽然是不同的执⾏流,但因为办理的都是⼀家公司的业务,所以票据是共享着的。这个就是多线程和多进程的最⼤区别。
  • 进程是系统分配资源的最⼩单位,线程是系统调度的最⼩单位。
  • ⼀个进程挂了⼀般不会影响到其他进程. 但是⼀个线程挂了, 可能把同进程内的其他线程⼀起带⾛(整个进程崩溃).

4) Java 的线程 和 操作系统线程 的关系

        线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对⽤⼾层提供了⼀些 API 供用户使⽤(例如 Linux 的 pthread 库).
api:application programming interface(应用程序编程接口)
  1. 操作系统提供的原生api是c写的
  2. 不同操作系统的线程api不相同
Java 标准库中 Thread 类 可以视为是对操作系统提供的 API 进⾏了进⼀步的抽象和封装.(Thread类就在Java默认导入的java.lang包里面)

2 第⼀个多线程程序

感受多线程程序和普通程序的区别:
  • 每个线程都是⼀个独⽴的执⾏流
  • 多个线程之间是 "并发" 执⾏的.
  使⽤ jconsole 命令观察线程

3 创建线程

⽅法1 继承 Thread 类

(1)继承 Thread 来创建⼀个线程类.
class MyThread extends Thread{@Override//run相当于线程的入口函数public void run() {System.out.println("hello world");}
}

(2)创建 MyThread 类的实例

Thread t=new MyThread();

(3)调⽤ start ⽅法启动线程

 //真正在系统中创建出一个线程t.start();

(4)休眠

 try {Thread.sleep(1000);//sleep是静态方法,表示休眠,休息一会再执行,用ms为单位} catch (InterruptedException e) {throw new RuntimeException(e);}

(5)run

        在执行线程时,不需要显示运行run方法,JVM自动调用

Tip:

在自己写的MyThread类里面不允许用throws,只能try-catch,因为其父类Thread里面没有实现该功能,但main函数中可以

实际开发中,异常的处理方式
1.记录异常信息作为日志.后续程序员根据日志调查问题
        程序仍然正常往后执行逻辑,不会因为这个异常就终止(对于服务器非常关键的)

2.进行重试,有的异常是概率性的(网络通讯)

3.特别严重的问题,必须立即马上处理的问题

        通过短信/邮件/微信/电话 通知程序员 (报警机制)


服务器和客户端指的是两个程序

服务器(server):被动接受请求,返回响应的一方

客户端(client):主动发起请求的一方

  • 客户端给服务器发送的数据,叫做“request"请求
  • 服务器给客户端返回的叫做“response”响应
  • 通常一个服务器可以给多个客户端提供服务
  • 服务器基本7*24待命

根据输出可以知道:多个线程的调度是随机的(“抢占式执行”)


Q:可以控制输出顺序吗?

A:输出顺序是操作系统内核的调度器控制的,没法在应用应用程序中编写代码控制 (调度器没有提供 api 的)
唯一能做的就是给线程设置优先级(但是优先级,对于操作系统来说,也是仅供参考,不会严格的定量的遵守)


如果直接使用run方法,而没有start,那么MyTread实质上没有创建出进程,只有main进程,遇到run中的死循环之后无法退出。

package Thread;
class MyThread extends Thread{@Override//run相当于线程的入口函数public void run() {while(true){System.out.println("hello run");try {Thread.sleep(1000);//sleep是静态方法,表示休眠,休息一会再执行,用ms为单位} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class demo1 {public static void main(String[] args) throws InterruptedException {Thread t=new MyThread();//真正在系统中创建出一个线程//t.start();t.run();while(true){System.out.println("hello main");Thread.sleep(1000);}}
}

⽅法2 实现 Runnable 接⼝

1. 实现 Runnable 接⼝
class MyRunnable implements Runnable{@Overridepublic void run() {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}

2. 创建 Thread 类实例, 调⽤ Thread 的构造⽅法时将 Runnable 对象作为 target 参数.

Runnable runnable=new MyRunnable();
Thread t=new Thread(runnable);

3. 调⽤ start ⽅法

 t.start();

总代码:

package Thread;
class MyRunnable implements Runnable{@Overridepublic void run() {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}public class demo2 {public static void main(String[] args) throws InterruptedException {Runnable runnable=new MyRunnable();Thread t=new Thread(runnable);t.start();while (true){System.out.println("hello main");Thread.sleep(1000);}}
}

Runnable最终还是要通过 Thread,真正创建线程

线程里要干啥, 通过 Runnable 来表示(而不是通过直接重写 Thread的run 来表示了)

Q:如何判断是用哪种?

A:根据线程要执行的任务的定义,是放到 Thread 里面,还是放到外面(Runnable 中)

Q:使用Runnable有什么好处吗?

A:解耦合。要执行的任务本身,和 线程这个概念,能够解耦合,从而后续如果变更代码.(比如不通过线程执行这个任务,通过其他方式.….)

采用 Runnable 这样的方案,代码的修改就会更简单.

对⽐上⾯两种⽅法:

  • 继承 Thread 类, 直接使⽤ this 就表⽰当前线程对象的引⽤.
  • 实现 Runnable 接⼝, this 表⽰的是 MyRunnable 的引⽤. 需要使⽤Thread.currentThread()

⽅法3 实现Tread的匿名内部类

package Thread;public class demo3 {public static void main(String[] args) throws InterruptedException {Thread thread=new Thread(){while(true){System.out.println("hello run");try {Thread.sleep(1000);//sleep是静态方法,表示休眠,休息一会再执行,用ms为单位} catch (InterruptedException e) {throw new RuntimeException(e);}}};thread.start();while(true){System.out.println("hello main");Thread.sleep(1000);}}
}

⽅法4 匿名内部类创建 Runnable ⼦类对象

 
package Thread;public class demo4 {public static void main(String[] args) throws InterruptedException {Runnable runnable = new Runnable() {@Overridepublic void run() {while (true) {System.out.println("hello run");try {Thread.sleep(1000);//sleep是静态方法,表示休眠,休息一会再执行,用ms为单位} catch (InterruptedException e) {throw new RuntimeException(e);}}}};Thread thread=new Thread(runnable);thread.start();while(true){System.out.println("hello main");Thread.sleep(1000);}}
}

⽅法5  lambda 表达式创建 Runnable ⼦类对象

package Thread;public class demo5 {public static void main(String[] args) throws InterruptedException {Thread thread=new Thread(()->{while (true) {System.out.println("hello run");try {Thread.sleep(1000);//sleep是静态方法,表示休眠,休息一会再执行,用ms为单位} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();while(true){System.out.println("hello main");Thread.sleep(1000);}}
}

4 多线程的优势-增加运⾏速度

可以观察多线程在⼀些场合下是可以提⾼程序的整体运⾏效率的。
  • 使⽤ System.nanoTime() 可以记录当前系统的 纳秒 级时间戳.
  • serial 串⾏的完成⼀系列运算.
  • concurrency 使⽤两个线程并⾏的完成同样的运算.
 

二. Thread 类及常⻅⽅法

      

        Thread 类是 JVM ⽤来管理线程的⼀个类,换句话说,每个线程都有⼀个唯⼀的 Thread 对象与之关联。

        ⽤我们上⾯的例⼦来看,每个执⾏流,也需要有⼀个对象来描述,类似下图所⽰,⽽ Thread 类的对象就是⽤来描述⼀个线程执⾏流的,JVM 会将这些 Thread 对象组织起来,⽤于线程调度,线程管理。

1 Thread 的常⻅构造⽅法

Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");

main方法结束了,主线程就结束了

以前认知里main方法结束,程序就执行完毕是针对单线程程序的

2 Thread 的⼏个常⻅属性

  • ID 是线程的唯⼀标识,不同线程不会重复
  • 名称是各种调试⼯具⽤到
  • 状态表⽰线程当前所处的⼀个情况,下⾯我们会进⼀步说明
  • 优先级⾼的线程理论上来说更容易被调度到
  • 关于后台线程,需要记住⼀点:JVM会在⼀个进程的所有⾮后台线程结束后,才会结束运⾏。
  • 是否存活,即简单的理解,为 run ⽅法是否运⾏结束了
  • 线程的中断问题,下⾯我们进⼀步说明
 
public class ThreadDemo {public static void main(String[] args) {Thread thread = new Thread(() -> {for (int i = 0; i < 10; i++) {try {System.out.println(Thread.currentThread().getName() + ": 我还在");Thread.sleep(1 * 1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + ": 我即将死去");});System.out.println(Thread.currentThread().getName()+ ": ID: " + thread.getId());System.out.println(Thread.currentThread().getName()+ ": 名称: " + thread.getName());System.out.println(Thread.currentThread().getName()+ ": 状态: " + thread.getState());System.out.println(Thread.currentThread().getName()+ ": 优先级: " + thread.getPriority());System.out.println(Thread.currentThread().getName()+ ": 后台线程: " + thread.isDaemon());System.out.println(Thread.currentThread().getName()+ ": 活着: " + thread.isAlive());System.out.println(Thread.currentThread().getName()+ ": 被中断: " + thread.isInterrupted());thread.start();while (thread.isAlive()) {}System.out.println(Thread.currentThread().getName()+ ": 状态: " + thread.getState());}
}

3 启动⼀个线程 - start()

之前我们已经看到了如何通过覆写 run ⽅法创建⼀个线程对象,但线程对象被创建出来并不意味着线程就开始运⾏了。

  • 覆写 run ⽅法是提供给线程要做的事情的指令清单
  • 线程对象可以认为是把 李四、王五叫过来了
  • ⽽调⽤ start() ⽅法,就是喊⼀声:”⾏动起来!“,线程才真正独⽴去执⾏了。

调⽤ start ⽅法, 才真的在操作系统的底层创建出⼀个线程

4 中断⼀个线程

        李四⼀旦进到⼯作状态,他就会按照⾏动指南上的步骤去进⾏⼯作,不完成是不会结束的。但有时我们需要增加⼀些机制,例如⽼板突然来电话了,说转账的对⽅是个骗⼦,需要赶紧停⽌转账,那张三该如何通知李四停⽌呢?这就涉及到我们的停⽌线程的⽅式了。

⽬前常⻅的有以下两种⽅式:

  • 通过共享的标记来进⾏沟通
  • 调⽤ interrupt() ⽅法来通知

⽰例1: 使⽤⾃定义的变量来作为标志位.

//需要给标志位上加 volatile 关键字(这个关键字的功能后⾯介绍).
public class ThreadDemo {private static class MyRunnable implements Runnable {public volatile boolean isQuit = false;@Overridepublic void run() {while (!isQuit) {System.out.println(Thread.currentThread().getName()+ ": 别管我,我忙着转账呢!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName()+ ": 啊!险些误了⼤事");}}public static void main(String[] args) throws InterruptedException {MyRunnable target = new MyRunnable();Thread thread = new Thread(target, "李四");System.out.println(Thread.currentThread().getName()+ ": 让李四开始转账。");thread.start();Thread.sleep(10 * 1000);System.out.println(Thread.currentThread().getName()+ ": ⽼板来电话了,得赶紧通知李四对⽅是个骗⼦!");target.isQuit = true;}
}

⽰例-2: 使⽤ Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替⾃定义标志位.

Thread 内部包含了⼀个 boolean 类型的变量作为线程是否被中断的标记.

使⽤ thread 对象的 interrupted() ⽅法通知线程结束.
public class ThreadDemo {private static class MyRunnable implements Runnable {@Overridepublic void run() {// 两种⽅法均可以while (!Thread.interrupted()) {
//while (!Thread.currentThread().isInterrupted()) {System.out.println(Thread.currentThread().getName() + ": 别管我,我忙着转账呢!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();System.out.println(Thread.currentThread().getName() + ": 有内⻤,终⽌交易!");// 注意此处的 breakbreak;}}System.out.println(Thread.currentThread().getName() + ": 啊!险些误了⼤事");}}public static void main(String[] args) throws InterruptedException {MyRunnable target = new MyRunnable();Thread thread = new Thread(target, "李四");System.out.println(Thread.currentThread().getName() + ": 让李四开始转账。");thread.start();Thread.sleep(10 * 1000);System.out.println(Thread.currentThread().getName() + ": ⽼板来电话了,得赶紧通知李四对⽅是个骗⼦!");thread.interrupt();}
}

thread 收到通知的⽅式有两种:

1. 如果线程因为调⽤ wait/join/sleep 等⽅法⽽阻塞挂起,则以 InterruptedException 异常的形式通 知,清除中断标志

        ◦ 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程.

          ◦ Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

2. 否则,只是内部的⼀个中断标志被设置,thread 可以通过这种⽅式通知收到的更及时,即使线程正在 sleep 也可以⻢上收到。

      

5 等待⼀个线程 - join()

有时,我们需要等待⼀个线程完成它的⼯作后,才能进⾏⾃⼰的下⼀步⼯作。例如,张三只有等李四转账成功,才决定是否存钱,这时我们需要⼀个⽅法明确等待线程的结束。

package Thread;public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {Runnable target =() -> {for (int i = 0; i < 10; i++) {try {System.out.println(Thread.currentThread().getName()+ ": 我还在⼯作!");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + ": 我结束了!");};Thread thread1 = new Thread(target, "李四");Thread thread2 = new Thread(target, "王五");System.out.println("先让李四开始⼯作");thread1.start();thread1.join();System.out.println("李四⼯作结束了,让王五开始⼯作");thread2.start();thread2.join();System.out.println("王五⼯作结束了");}
}

⼤家可以试试如果把两个 join 注释掉,现象会是怎么样的呢?

附录

6 获取当前线程引⽤

这个⽅法我们已经⾮常熟悉了

public class ThreadDemo {public static void main(String[] args) {Thread thread = Thread.currentThread();System.out.println(thread.getName());}
}

7 休眠当前线程

也是我们⽐较熟悉⼀组⽅法,有⼀点要记得,因为线程的调度是不可控的,所以,这个⽅法只能保证实际休眠时间是⼤于等于参数设置的休眠时间的。
 
public class ThreadDemo {public static void main(String[] args) throws InterruptedException {System.out.println(System.currentTimeMillis());Thread.sleep(3 * 1000);System.out.println(System.currentTimeMillis());}
}

三、 线程的状态

1 观察线程的所有状态

线程的状态是⼀个枚举类型
 
Thread.State
public class ThreadState {public static void main(String[] args) {for (Thread.State state : Thread.State.values()) {System.out.println(state);}}
}

  • NEW: 安排了⼯作, 还未开始⾏动
  • RUNNABLE: 可⼯作的. ⼜可以分成正在⼯作中和即将开始⼯作.
  • BLOCKED: 这⼏个都表⽰排队等着其他事情
  • WAITING: 这⼏个都表⽰排队等着其他事情
  • TIMED_WAITING: 这⼏个都表⽰排队等着其他事情
  • TERMINATED: ⼯作完成了.

2. 线程状态和状态转移的意义

⼤家不要被这个状态转移图吓到,我们重点是要理解状态的意义以及各个状态的具体意思。

还是我们之前的例⼦:

刚把李四、王五找来,还是给他们在安排任务,没让他们⾏动起来,就是 NEW 状态;

当李四、王五开始去窗⼝排队,等待服务,就进⼊到 RUNNABLE 状态。该状态并不表⽰已经被银⾏⼯作⼈员开始接待,排在队伍中也是属于该状态,即可被服务的状态,是否开始服务,则看调度器的调度;

当李四、王五因为⼀些事情需要去忙,例如需要填写信息、回家取证件、发呆⼀会等等时,进⼊BLOCKED 、 WATING 、TIMED_WAITING 状态,⾄于这些状态的细分,我们以后再详解;

如果李四、王五已经忙完,为 TERMINATED 状态。

所以,之前我们学过的 isAlive() ⽅法,可以认为是处于不是 NEW 和 TERMINATED 的状态都是活着的

3 观察线程的状态和转移

观察 1: 关注 NEW RUNNABLE TERMINATED 状态的转换  
package Thread;public class ThreadStateTransfer {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for (int i = 0; i < 1000_0000; i++) {}}, "李四");System.out.println(t.getName() + ": " + t.getState());;t.start();while (t.isAlive()) {System.out.println(t.getName() + ": " + t.getState());;}System.out.println(t.getName() + ": " + t.getState());;}
}


观察 2: 关注 WAITING BLOCKED TIMED_WAITING 状态的转换
 public static void main(String[] args) {final Object object = new Object();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (object) {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}}, "t1");t1.start();Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (object) {System.out.println("hehe");}}}, "t2");t2.start();}
}

使⽤ jconsole 可以看到 t1 的状态是 TIMED_WAITING , t2 的状态是 BLOCKED

修改上⾯的代码, 把 t1 中的 sleep 换成 wait
 
    public static void main(String[] args) {final Object object = new Object();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (object) {try {// [修改这⾥就可以了!!!!!]// Thread.sleep(1000);object.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}, "t1");
...}

使⽤ jconsole 可以看到 t1 的状态是 WAITING

结论:

BLOCKED 表⽰等待获取锁, WAITING 和 TIMED_WAITING 表⽰等待其他线程发来通知.

TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在⽆限等待唤醒

相关文章:

【JavaEE初阶】线程 和 thread

本节⽬标 认识多线程 掌握多线程程序的编写 掌握多线程的状态 一. 认识线程&#xff08;Thread&#xff09; 1概念 1) 线程是什么 ⼀个线程就是⼀个 "执⾏流". 每个线程之间都可以按照顺序执⾏⾃⼰的代码. 多个线程之间 "同时" 执⾏着多份代码. 还…...

【IMU:视觉惯性SLAM系统】

视觉惯性SLAM系统简介 相机&#xff08;单目/双目/RGBD)与IMU结合起来就是视觉惯性&#xff0c;通常以单目/双目IMU为主。 IMU里面有个小芯片可以测量角速度与加速度&#xff0c;可分为6轴(6个自由度)和9轴&#xff08;9个自由度&#xff09;IMU&#xff0c;具体的关于IMU的介…...

【python实现烟花】

可以使用 Python 的 turtle 模块来实现烟花效果。下面是一个简单的示例代码&#xff0c;展示如何用 turtle 绘制烟花&#xff1a; import turtle import random# 设置屏幕 screen turtle.Screen() screen.bgcolor("black")# 创建烟花函数 def draw_firework(x, y):…...

OpenCV学习——图像融合

import cv2 as cv import cv2 as cvbg cv.imread("test_images/background.jpg", cv.IMREAD_COLOR) fg cv.imread("test_images/forground.png", cv.IMREAD_COLOR)# 打印图片尺寸 print(bg.shape) print(fg.shape)resize_size (1200, 800)bg cv.resize…...

CS 144 check6: buiding an IP router

Lecture Notes Exercises 路由器的任务是根据路由表转发接收到的数据报&#xff1a;路由表是一系列规则&#xff0c;用于指导路由器针对任何给定的数据报应如何进行转发。 发送出什么接口。下一跳的IP地址。 这个check的工作是实现一个路由器&#xff0c;它可以为任何给定的…...

Pytorch | 从零构建ResNet对CIFAR10进行分类

Pytorch | 从零构建ResNet对CIFAR10进行分类 CIFAR10数据集ResNet核心思想网络结构创新点优点应用 ResNet结构代码详解结构代码代码详解BasicBlock 类ResNet 类ResNet18、ResNet34、ResNet50、ResNet101、ResNet152函数 训练过程和测试结果代码汇总resnet.pytrain.pytest.py 前…...

Spring整合Redis基本操作步骤

Spring 整合 Redis 操作步骤总结 1. 添加依赖 首先&#xff0c;在 pom.xml 文件中添加必要的 Maven 依赖。Redis 相关的依赖包括 Spring Boot 的 Redis 启动器和 fastjson&#xff08;如果需要使用 Fastjson 作为序列化工具&#xff09;&#xff1a; <!-- Spring Boot Re…...

java中的方法的重载和重写、构造器

目录 方法的重载和重写、构造器1.java的修饰符&#xff1a;2.普通方法3.构造器&#xff08;也叫构造方法/构造函数&#xff09;4.方法的重载5.补充6.方法的重写7.类的执行顺序8.再看方法的重写 方法的重载和重写、构造器 1.java的修饰符&#xff1a; public修饰的代码&#xf…...

Vite 系列课程|1课程道路,2什么是构建工具

Vite 系列课程 1. 课程导论 1.1 为什么要学习 Vite&#xff1f; 1.1.1 Webpack vs. Vite&#xff1a;新旧霸主的交替&#xff1f; Webpack 长期以来一直是前端构建工具的事实标准&#xff0c;拥有庞大的用户群体、成熟的生态系统和丰富的学习资源。然而&#xff0c;随着前端技术…...

【蓝桥杯选拔赛真题96】Scratch风车旋转 第十五届蓝桥杯scratch图形化编程 少儿编程创意编程选拔赛真题解析

目录 scratch风车旋转 一、题目要求 编程实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、python资料 scratc…...

SQL血缘解析

Druid 作为使用率特别高的的数据库连接池工具,在具备完善的连接池管理功能外,同时Druid 的 SQL解析功能可以用来防止 SQL注入等安全风险。通过对 SQL 语句进行解析和检查,Druid 可以识别并阻止潜在的恶意 SQL 语句执行,黑名单(阻止特定的 SQL 语句执行)、白名单(仅允许特…...

Docker 部署机器学习模型

1.编写机器学习代码 &#xff08;1&#xff09;新建一个 mlmodel.py import numpy as np import pandas as pd from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sk…...

leetcode 面试经典 150 题:无重复字符的最长子串

链接无重复字符的最长子串题序号3类型字符串解题方法滑动窗口难度中等 题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 …...

LeetCode 283. 移动零 (C++实现)

1. 题目描述 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1&#xff1a; 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 …...

基于Spring Boot的个人财务系统

一、系统背景与目的 随着全球经济的发展和人们生活水平的提高&#xff0c;个人财务管理变得越来越重要。传统的个人财务软件存在操作复杂、用户体验差、数据不安全等问题&#xff0c;无法满足用户的个性化需求。因此&#xff0c;开发一种基于Spring Boot的个人财务系统&#x…...

【计算机网络2】计算机网络的性能能指标

目录 一 、计算机网络的性能指标 二、具体介绍 1、速 率 2、带 宽 3、吞 吐 量 4、时 延 5、时延带宽积 6、往 返 时 延 7、信道利用率 一 、计算机网络的性能指标 计算机网络的性能指标就是从不同方面度量计算机网络的性能&#xff0c;有如下7个指标&#xff1a; 速…...

Axure RP9 的详细安装及Axure入门应用

文章目录 一、Axure 是什么?二、Axure 的应用场景三、Axure 安装1. 下载安装2. 汉化授权 附&#xff1a;下载链接 一、Axure 是什么? 1、Axure 是一种强大的原型设计工具&#xff0c;它可以帮助设计师和产品经理快速创建交互式的、高保真度的原型&#xff0c;并进行用户体验…...

Scala学习记录 如何打印输出

在Scala中&#xff0c;打印输出可以通过多种方式实现&#xff0c;以下是一些常见的打印输出方法&#xff1a; 1.使用printf()方法&#xff1a; 这是一种传统的C语言风格的打印方式&#xff0c;通过格式化字符串来控制输出的格式。例如&#xff0c;printf("整数&#xff1a…...

内网IP段介绍与汇总

IPV4内网段 IP地址段地址范围地址数量用途描述0.0.0.0/80.0.0.0–0.255.255.25516777216SoftwareCurrent network (only valid as source address).10.0.0.0/810.0.0.0–10.255.255.25516777216Private networkUsed for local communications within a private network.100.64…...

js常用方法之: 预览大图(uniapp原生方法封装)

方法: //预览图片 pic可传单个图片地址字符串 或 图片数组(带index) previewPic: function(pic, index) {if (!pic) return;if (index undefined) {let array [];array.push(pic);uni.previewImage({urls: array,current: array[0]});} else {uni.previewImage({urls: pic,…...

人脸生成3d模型 Era3D

从单视图图像进行3D重建是计算机视觉和图形学中的一项基本任务&#xff0c;因为它在游戏设计、虚拟现实和机器人技术中具有潜在的应用价值。早期的研究主要依赖于直接在体素上进行3D回归&#xff0c;这往往会导致过于平滑的结果&#xff0c;并且由于3D训练数据的限制&#xff0…...

「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件

本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息&#xff0c;页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。 关键词 UI互动应用天气预报数据绑定动态展示状态管理 一、功能说明 自定义…...

深圳龙岗戴尔dell r730xd服务器故障维修

深圳龙岗一台DELL POWEREDGE R730XD服务器系统故障问题处理&#xff1a; 1&#xff1a;客户工厂年底产线整改&#xff0c;时不时的会意外断电&#xff0c;导致服务器也频繁停机&#xff0c; 2&#xff1a;多次异常停机后导致服务器开机后windows server系统无法正常启动了&…...

lxml提取某个外层标签里的所有文本

html如下 <div data-v-1cf6f280"" class"analysis-content">选项D错误&#xff1a;<strong>在衡量通货膨胀时&#xff0c;</strong><strong>消费者物价指数使用得最多、最普遍</strong>。 </div> 解析html文本 fro…...

【AI图像生成网站Golang】项目测试与优化

AI图像生成网站 目录 一、项目介绍 二、雪花算法 三、JWT认证与令牌桶算法 四、项目架构 五、图床上传与图像生成API搭建 六、项目测试与优化 六、项目测试与优化 在开发过程中&#xff0c;性能优化是保证项目可扩展性和用户体验的关键步骤。本文将详细介绍我如何使用一…...

使用Docker启用MySQL8.0.11

目录 一、Docker减小镜像大小的方式 1、基础镜像选择 2、减少镜像层数 3、清理无用文件和缓存 4、优化文件复制&#xff08;COPY和ADD指令&#xff09; 二、Docker镜像多阶段构建 1、什么是dockers镜像多阶段构建 1.1 概念介绍 1.2 构建过程和优势 2、怎样在Dockerfil…...

部署Mysql、镜像和容器、常见命令

目录 部署Mysql 镜像和容器 常见命令 部署Mysql 可以有多个容器 docker run -d \--name mysql \-p 3306:3306 \-e TZAsia/Shanghai \-e MYSQL_ROOT_PASSWORD123 \mysql docker run -d \--name mysql2 \-p 3307:3307 \-e TZAsia/Shanghai \-e MYSQL_ROOT_PASSWORD123 \mys…...

Windows部署Docker及PostgreSQL数据库相关操作

一、Windows安装Docker 1.wsl安装 以管理员身份启动命令行&#xff0c;运行&#xff1a;wsl --install&#xff1b; 安装结束后&#xff0c;重启电脑&#xff0c;以管理员身份启动命令行&#xff0c;运行&#xff1a;wsl --install -d Ubuntu&#xff1b; 中间需要输入用户名…...

Halcon例程代码解读:安全环检测(附源码|图像下载链接)

安全环检测核心思路与代码详解 项目目标 本项目的目标是检测图像中的安全环位置和方向。通过形状匹配技术&#xff0c;从一张模型图像中提取安全环的特征&#xff0c;并在后续图像中识别多个实例&#xff0c;完成检测和方向标定。 实现思路 安全环检测分为以下核心步骤&…...

Unity3D用正则判断身份证号或邮箱

系列文章目录 unity工具 文章目录 系列文章目录👉前言👉一、正则判断邮箱格式👉二、正则判断身份证号👉壁纸分享👉总结👉前言 C#正则表达式(Regex)是一种用来匹配字符串模式的强大工具。在C#中,可以使用System.Text.RegularExpressions命名空间下的Regex类来处…...

PostgreSQL表达式的类型

PostgreSQL表达式是数据库查询中非常重要的组成部分&#xff0c;它们由一个或多个值、运算符和PostgreSQL函数组合而成&#xff0c;用于计算出一个单一的结果。这些表达式类似于公式&#xff0c;可以用查询语言编写&#xff0c;并用于查询数据库中的特定数据集。 PostgreSQL表…...

C++简明教程(文章要求学过一点C语言)(10)

类的教程 C 类的完整教程 C 中&#xff0c;类&#xff08;class&#xff09;是面向对象编程的核心概念&#xff0c;用于定义对象的属性&#xff08;数据成员&#xff09;和行为&#xff08;成员函数&#xff09;。本教程将带你从零开始&#xff0c;循序渐进地学习如何定义和使…...

从腾讯云的恶意文件查杀学习下PHP的eval函数

问题来自于腾讯云的主机安全通知&#xff1a; &#x1f680;一键接入&#xff0c;畅享GPT及AI大模型服务&#xff01;【顶级API中转品牌】&#xff1a; https://api.ablai.top/ 病毒文件副本内容如下&#xff1a; <?php function x($x){eval($x);}x(str_rot13(riny($_CBF…...

OpenWRT——官方镜像安装Docker(网络环境需设置)并配置Sun-Panel

Pro更多功能预览地址https://pro.sun-panel.top/#/hpage/pro Github地址https://github.com/hslr-s/sun-panel?tabreadme-ov-file 首先确认宿主机网络环境符合要求 curl Google.com1.确认没问题后开始安装Docker opkg update opkg install dockerd docker luci-app-docker…...

MySQL 中的常见错误与排查

在 MySQL 数据库的日常运维中&#xff0c;管理员可能会遇到各种错误。无论是查询性能问题、连接异常、数据一致性问题&#xff0c;还是磁盘空间不足等&#xff0c;及时排查并解决这些问题是保证数据库稳定运行的关键。本文将列出 MySQL 中一些常见的错误及其排查方法。 一、连接…...

workman服务端开发模式-应用开发-gateway长链接端工作原理

一、长链接的工作原理 Register类其实也是基于基础的Worker开发的。Gateway进程和BusinessWorker进程启动后分别向Register进程注册自己的通讯地址&#xff0c;Gateway进程和BusinessWorker通过Register进程得到通讯地址后&#xff0c;就可以建立起连接并通讯了。而Gateway进程…...

8位移位寄存器的verilog语言

module shift_register (output reg [7:0] Q, // 8位移位寄存器输出input D, // 输入数据input rst, // 复位信号input clk // 时钟信号 );always (posedge clk) beginif (!rst)Q < 8b00000000; // 复位时将Q清零elseQ < {Q[6:0], D}; // 否则…...

Android学习(五)-Kotlin编程语言-面向对象中的 继承-构造函数-接口三模块学习

首先&#xff0c;我们需要定义一个 Person 类&#xff1a; open class Person {var name ""var age 0fun eat() {println("$name is eating.")} } 注意&#xff0c;Person 类前面加上了 open 关键字&#xff0c;表示这个类可以被继承。在 Kotlin 中&am…...

Java 集合框架中的 List、ArrayList 和 泛型 实例

— Java 集合框架中的 List、ArrayList 和 泛型 在 Java 中&#xff0c;集合框架提供了许多不同类型的集合类&#xff0c;用于存储和操作对象。List 和 ArrayList 是最常用的两种集合类型&#xff0c;而泛型&#xff08;Generics&#xff09;则是 Java 中的一项重要特性&…...

计算机网络-L2TP VPN基础概念与原理

一、概述 前面学习了GRE和IPSec VPN&#xff0c;今天继续学习另外一个也很常见的VPN类型-L2TP VPN。 L2TP&#xff08;Layer 2 Tunneling Protocol&#xff09; 协议结合了L2F协议和PPTP协议的优点&#xff0c;是IETF有关二层隧道协议的工业标准。L2TP是虚拟私有拨号网VPDN&…...

【Rust自学】4.4. 引用与借用

4.4.0 写在正文之前 这一节的内容其实就相当于C的智能指针移动语义在编译器层面做了一些约束。Rust中引用的写法通过编译器的约束写成了C中最理想、最规范的指针写法。所以学过C的人对这一章肯定会非常熟悉。 喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文…...

LLaMA-Factory 单卡3080*2 deepspeed zero3 微调Qwen2.5-7B-Instruct

环境安装 git clone https://gitcode.com/gh_mirrors/ll/LLaMA-Factory.gitcd LLaMA-Factorypip install -e ".[torch,metrics]"pip install deepspeed 下载模型 pip install modelscope modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir /roo…...

[python SQLAlchemy数据库操作入门]-12.直接执行 SQL 语句处理股票数据

哈喽,大家好,我是木头左! 1. SQLAlchemy Core 简介 SQLAlchemy Core 是 SQLAlchemy 库的一个模块,它允许用户直接执行 SQL 语句而不必使用 ORM(对象关系映射)。对于需要精细控制 SQL 查询或处理复杂数据库操作的情况,SQLAlchemy Core 提供了一种灵活而强大的方式来与数…...

【Unity3D】实现可视化链式结构数据(节点数据)

关键词&#xff1a;UnityEditor、可视化节点编辑、Unity编辑器自定义窗口工具 使用Newtonsoft.Json、UnityEditor相关接口实现 主要代码&#xff1a; Handles.DrawBezier(起点&#xff0c;终点&#xff0c;起点切线向量&#xff0c;终点切线向量&#xff0c;颜色&#xff0c;n…...

C# WinForm移除非法字符的输入框

C# WinForm移除非法字符的输入框 文章目录 namespace System.Windows.Forms {using System.ComponentModel;/// <summary>/// 支持移除 非法字符 的输入框。/// </summary>public class RemoveInvalidCharTextBox : TextBox{/// <summary>/// 测试代码&#…...

linux安装宝塔面板及git

宝塔面板安装教程&#xff1a;https://www.bt.cn/new/download.html?bt_lybaidu&sdclkidALfs15q615oG15As&bd_vid9358688624393223862 Centos/OpenCloud/Alibaba稳定版9.0.0 urlhttps://download.bt.cn/install/install_lts.sh;if [ -f /usr/bin/curl ];then curl -s…...

GoTime#34期 Pachyderm, Provenance, Data Lakes

本篇内容是根据2017年2月份#34 Pachyderm, Provenance, Data Lakes音频录制内容的整理与翻译 Joe Doliner 加入了节目&#xff0c;谈论使用 Pachyderm 管理数据湖、数据容器、溯源(provenance) 以及其他有趣的 Go 项目和新闻。 Erik St. Martin: 大家好&#xff0c;欢迎收听新…...

数据库的三范式是什么?

第一范式&#xff08;1NF&#xff09; 每列的原子性&#xff0c;表中的每一个字段都是不可分割的&#xff0c;同一列中不能有多个值。第一范式是对关系模式的基本要求&#xff0c;不满足第一范式的数据库不是关系型数据库。 ・不满足第一范式的示例&#xff1a; 学生编号 学生…...

LOS/NLOS环境建模与三维TOA定位,MATLAB仿真程序,可自定义锚点数量和轨迹点长度

本代码的主要功能是建模 LOS&#xff08;视距&#xff09;和 NLOS&#xff08;非视距&#xff09;环境下的定位系统&#xff0c;估计目标的动态位置&#xff0c;三维空间 文章目录 运行结果源代码代码介绍 总结 运行结果 10个点的轨迹定位&#xff1a; 50个点的轨迹定位&#…...

css

已经学完html了&#xff0c;继续学习前端三剑客html、css、js之一的css。&#x1f600; 1、什么是css css&#xff1a;用于网页结构的布局和修饰的一种样式脚本 层叠样式表&#xff1a;(英文全称&#xff1a;Cascading Style Sheets)&#xff0c; 简称&#xff1a;样式表&…...