多线程学习篇二:Thread常见方法

1. 常见方法

方法名

static

功能说明

注意点

start()

启动一个新线程,在新线程里面运行run方法

start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的 start 方法只能调用一次,如果调用了多次会出现 IllegalThreadStateException

run()

新线程启动后会调用的方法

如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建Thread的子类对象,来覆盖默认行为

join()

等待线程运行结束

join(long n)

等待线程运行结束,最多等待n毫秒

getId()

获取线程长整型的id

id 唯一

getName()

获取线程名

setName(String)

设置线程名

getPriority()

获取线程优先级

setPriority(int)

修改线程优先级

Java 中规定线程优先级是1-10的整数,较大的优先级
能提高该线程被 CPU调度的机率

getState()

获取线程状态

Java 中线程状态有6个,分别为:NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED

isInterrupted()

判断是否被打断

不会清除打断标记

interrupt()

打断线程

如果被打断线程正在 sleep 、wait 、join 会导致被打断的线程抛出InterruptedException,并清除打断标记。如果打断的正在运行的线程,则会设置打断标记。park的线程被打断,也会设置打断标记

interrupted()

static

判断当前线程是否被打断

会清除打断标记

isAlive()

线程是否存活

sleep(long n)

static

让当前执行的线程休眠n毫秒,休眠时让出 cpu的时间片给其它线程

yield()

static

提示线程调度器让出当前线程对 CPU 的使用

主要是为了测试和调试

currentThread()

static

获取当前正在执行的线程

2. 方法演示

2.1 setName 与 getName

2.1.1 默认情况下的线程名
@Slf4j
public class Test01 {public static void main(String[] args) {new Thread(() -> log.info(Thread.currentThread().getName())).start();log.info(Thread.currentThread().getName());}}

默认情况下,主线程名称为 main,其他线程名为 Thread-n 的形式,其中 n 为从 0 开始的整型,可以通过 setName 方法进行修改

2.1.2 修改默认线程名
@Slf4j
public class Test02 {public static void main(String[] args) {Thread.currentThread().setName("m1");Thread thread = new Thread(() -> log.info(Thread.currentThread().getName()), "t1");thread.start();log.info(Thread.currentThread().getName());}
}

自定义线程名设置成功

2.2 run 与 start

2.2.1 执行 start 方法
@Slf4j
public class Test03 {public static void main(String[] args) {Thread thread = new Thread(() -> log.info(Thread.currentThread().getName()));thread.start();}
}

在新线程中执行 run 方法的代码逻辑

 2.2.2 执行 run 方法
@Slf4j
public class Test03 {public static void main(String[] args) {Thread thread = new Thread(() -> log.info(Thread.currentThread().getName()));thread.run();}
}

在主线程中执行 run 方法的代码逻辑,相当于普通方法

2.3 sleep 与 yield

2.3.1 sleep
  • 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
  • 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出InterruptedException
  • 睡眠结束后的线程未必会立刻得到执行
  • 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性
2.3.2 yield
  • 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程
  • 具体的实现依赖于操作系统的任务调度器
2.3.3 sleep方法的应用 (限制对CPU的使用)
2.3.3.1 不使用 sleep 方法,cpu的使用情况
public class Test04 {public static void main(String[] args) {new Thread(() -> {while (true) {
//                try {
//                    Thread.sleep(50);
//                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
//                }}}).start();}
}

.java 源文件未指定 package,并且 CLASSPATH 存在 .:(当前路径),执行以下步骤:

  1. 将文件 Test04.java 上传到 Linux 服务器 
  2. 执行命令 javac Test04.java (编译 .java 文件)
  3. 执行命令 java Test04 (运行 Test04 的 main 方法)

如果指定了package,执行以下步骤:

  1. 将文件 Test04.java 上传到 Linux 服务器 
  2. 执行命令 javac Test04.java -d ./ (编译 .java 文件)
  3. 执行命令 java 类的全路径.Test04 (运行 Test04 的 main 方法)

通过 top 命令查看运行结果

CPU 占用飙升到 100%

2.3.3.2 不使用 sleep 方法(将相关注释去除),cpu的使用情况
public class Test04 {public static void main(String[] args) {new Thread(() -> {while (true) {try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}}).start();}
}

通过 top 命令查看运行结果

使用了 sleep 方法,尽管睡眠时间很短,但是 CPU 占用锐减

2.4 线程优先级

  • 线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
  • 如果 cpu 比较忙,那么优先级高的线程会获得更多的时间片,但 cpu 闲时,优先级几乎没作用
2.4.1 现象演示
@Slf4j
public class Test05 {public static void main(String[] args) {Thread t1 = new Thread(() -> {for (int i = 1; i <= 100; i++) {log.info(Thread.currentThread().getName() + ":" + i);}}, "t1");Thread t2 = new Thread(() -> {for (int i = 1; i <= 100; i++) {log.info(Thread.currentThread().getName() + ":" + i);}}, "t2");t1.setPriority(10);t2.setPriority(1);t1.start();t2.start();}
}

将 t1 的优先级设置到最大值 10,将 t2 的优先级设置到最大值 1

即使 t2 线程的优先级为最小值 1 ,也是有机会优先执行完

2.5 join

2.5.1 执行下列代码,RESULT 的结果是多少?
@Slf4j
public class Test06 {private static int RESULT = -1;public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {// 模拟业务处理逻辑try {TimeUnit.SECONDS.sleep(new Random().nextInt(3));} catch (InterruptedException e) {throw new RuntimeException(e);}RESULT = 1;}, "t1");t1.start();log.info("result : " + RESULT);}
}

运行结果为: -1

2.5.2 使用 sleep 方法行不行,为什么?

使用 sleep 方法不太合适,sleep 时间过长影响效率,sleep 时间过短拿不到正确结果

2.5.3 使用 join 方法

@Slf4j
public class Test06 {private static int RESULT = -1;public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {// 模拟业务处理逻辑try {TimeUnit.SECONDS.sleep(new Random().nextInt(3));} catch (InterruptedException e) {throw new RuntimeException(e);}RESULT = 1;}, "t1");t1.start();t1.join();log.info("result : " + RESULT);}
}

运行结果为: 1

2.5.3 join 方法耗时分析
2.5.3.1 案例1
@Slf4j
public class Test07 {private static int R1 = -1;private static int R2 = -1;public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}R1 = 1;}, "t1");Thread t2 = new Thread(() -> {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}R2 = 2;}, "t2");long start = System.currentTimeMillis();t1.start();t2.start();t1.join();t2.join();long end = System.currentTimeMillis();log.info("R1: {} R2: {} cost: {}s", R1, R2, (end - start) / 1000);}
}

一共耗时 2 s,图解如下:

运行到 t1 的 join 方法时,t1 运行结束,t2 已运行 1s,所以还需要等到 1s 就可以运行完毕

2.5.3.2 案例2

将 t1.join() 放入到线程 t2中

@Slf4j
public class Test08 {private static int R1 = -1;private static int R2 = -1;public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}R1 = 1;}, "t1");Thread t2 = new Thread(() -> {try {t1.join();TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}R2 = 2;}, "t2");long start = System.currentTimeMillis();t1.start();t2.start();t2.join();long end = System.currentTimeMillis();log.info("R1: {} R2: {} cost: {}s", R1, R2, (end - start) / 1000);}
}

一共耗时 3 s,图解如下(假设 t1 优先获得时间片): 

t2 线程需要等到 t1 线程执行完毕才可以执行,相当于同步执行 

2.5.4 有时间的 join
2.5.4.1 join 时间小于业务处理时间
@Slf4j
public class Test09 {private static int RESULT = -1;public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {// 模拟业务处理逻辑try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}RESULT = 1;}, "t1");t1.start();t1.join(1000);log.info("result : " + RESULT);}
}

获取默认值:-1

2.5.4.2 join 时间大于业务处理时间
@Slf4j
public class Test09 {private static int RESULT = -1;public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {// 模拟业务处理逻辑try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}RESULT = 1;}, "t1");t1.start();t1.join(2500);log.info("result : " + RESULT);}
}

获取处理后的值:1

2.6 interrupt、isInterrupted、interrupted

2.6.1 打断阻塞线程

sleep,wait,join 方法都会让线程进入阻塞状态,我们以 sleep 为例

@Slf4j
public class Test10 {public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {// 模拟业务处理逻辑try {TimeUnit.MILLISECONDS.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}, "t1");t1.start();TimeUnit.MILLISECONDS.sleep(500);t1.interrupt();log.info(" 打断状态: {}", t1.isInterrupted());}
}

运行结果:打断一个正在阻塞的线程,会抛出 InterruptedException,并且 interrupt 方法会清除打断标记 

PS:主线程的 sleep 时间和 t1 现成的睡眠差距稍微大点,否则 t1 线程就可能处于非阻塞状态,isInterrupted 方法将会返回 true

2.6.2 打断正常线程
@Slf4j
public class Test11 {public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {while (true) {Thread current = Thread.currentThread();boolean interrupted = current.isInterrupted();if (interrupted) {log.debug(" 打断状态: {}", interrupted);break;}}}, "t1");t1.start();TimeUnit.MILLISECONDS.sleep(500);t1.interrupt();}
}

运行结果:打断一个正在运行的的线程,isInterrupted 方法将会返回 true

2.6.3 打断 park 线程
@Slf4j
public class Test12 {public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {log.info("park...");LockSupport.park();log.info("打断状态:{}", Thread.currentThread().isInterrupted());}, "t1");t1.start();TimeUnit.MILLISECONDS.sleep(500);t1.interrupt();}
}

运行结果:打断一个正在 park 的的线程,isInterrupted 方法将会返回 true

如果一个线程的打断状态已经为 true,会发生什么现象?
@Slf4j
public class Test13 {public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {for (int i = 0; i < 3; i++) {log.info("park...");LockSupport.park();log.info("打断状态:{}", Thread.currentThread().isInterrupted());}}, "t1");t1.start();TimeUnit.MILLISECONDS.sleep(500);t1.interrupt();}
}

运行结果:通过打印日志的时间戳,我们可以看出来,如果一个线程的打断标记为 true,则 park 失效

将方法 isInterrupted 改成 interrupted
@Slf4j
public class Test13 {public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {for (int i = 0; i < 3; i++) {log.info("park...");LockSupport.park();log.info("打断状态:{}", Thread.interrupted());}}, "t1");t1.start();TimeUnit.MILLISECONDS.sleep(500);t1.interrupt();}
}

运行结果:t1 线程又被 park 住了

2.6.4 相关方法的应用 -- 两阶段终止模式
2.6.4.1 Two Phase Termination

在一个线程 T1 中如何 “优雅” 终止线程 T2?这里的 “优雅” 指的是给 T2 一个 “料理后事” 的机会。

2.6.4.2 错误思路
  • 使用线程对象的 stop() 方法停止线程:stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁
  • 使用 System.exit(int) 方法停止线程:目的仅是停止一个线程,但这种做法会让整个程序都停止
2.6.4.3 优雅停止
2.6.4.3.1 利用 isInterrupted
@Slf4j
public class TwoPhaseTermination01 {private Thread thread;public void start() {thread = new Thread(() -> {while (true) {Thread currentThread = Thread.currentThread();boolean interrupted = currentThread.isInterrupted();if (interrupted) {log.info("料理后事");break;}try {// 睡眠1sTimeUnit.MILLISECONDS.sleep(1000);log.info("保存数据");} catch (InterruptedException e) {currentThread.interrupt();}}}, "监控线程");thread.start();}public void stop() {thread.interrupt();}public static void main(String[] args) throws Exception {TwoPhaseTermination01 twoPhaseTermination01 = new TwoPhaseTermination01();twoPhaseTermination01.start();TimeUnit.MILLISECONDS.sleep(3500);log.info("stop");twoPhaseTermination01.stop();}
}

图解流程如下:

2.6.4.3.2 利用停止标记
@Slf4j
public class TwoPhaseTermination02 {private Thread thread;// 停止标记用 volatile 是为了保证该变量在多个线程之间的可见性private volatile boolean stop = false;public void start() {thread = new Thread(() -> {while (true) {if (stop) {log.info("料理后事");break;}try {// 睡眠1sTimeUnit.MILLISECONDS.sleep(1000);log.info("保存数据");} catch (InterruptedException ignore) {}}}, "监控线程");thread.start();}public void stop() {stop = true;thread.interrupt();}public static void main(String[] args) throws Exception {TwoPhaseTermination02 twoPhaseTermination02 = new TwoPhaseTermination02();twoPhaseTermination02.start();TimeUnit.MILLISECONDS.sleep(3500);log.info("stop");twoPhaseTermination02.stop();}
}

 图解流程如下:

2.7 getStatus

各种状态代码演示

@Slf4j
public class Test14 {public static void main(String[] args) throws Exception {synchronized (Test14.class) {Thread t1 = new Thread(() -> log.info(Thread.currentThread().getName()), "t1");Thread t2 = new Thread(() -> {while (true) {}}, "t2");Thread t3 = new Thread(() -> {try {TimeUnit.MINUTES.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}}, "t3");Thread t4 = new Thread(() -> {try {t2.join();log.info(Thread.currentThread().getName());} catch (InterruptedException e) {throw new RuntimeException(e);}}, "t4");Thread t5 = new Thread(() -> {synchronized (Test14.class) {log.info(Thread.currentThread().getName());}}, "t5");Thread t6 = new Thread(() -> log.info(Thread.currentThread().getName()), "t6");t2.start();t3.start();t4.start();t5.start();t6.start();TimeUnit.MILLISECONDS.sleep(500);log.info("t1 state {}", t1.getState());log.info("t2 state {}", t2.getState());log.info("t3 state {}", t3.getState());log.info("t4 state {}", t4.getState());log.info("t5 state {}", t5.getState());log.info("t6 state {}", t6.getState());}}
}

2.8 isAlive
@Slf4j
public class Test15 {public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {try {TimeUnit.MILLISECONDS.sleep(2000);log.info(Thread.currentThread().getName());} catch (InterruptedException e) {throw new RuntimeException(e);}}, "t1");t1.start();TimeUnit.MILLISECONDS.sleep(500);log.info("thread isAlive " + t1.isAlive());t1.join();log.info("thread isAlive " + t1.isAlive());}
}

得出结论:线程 t1 未执行完是存活的,当执行完业务逻辑方法返回 false 

2.9 守护线程
t1、t2 都是非守护线程
@Slf4j
public class Test16 {public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {for (int i = 1; i <= 10; i++) {log.info("t1 => " + i);}}, "t1");Thread t2 = new Thread(() -> {for (int i = 1; i <= 50; i++) {log.info("t2 => " + i);}}, "t2");t1.start();t2.start();}
}

当 t1、t2 都是非守护线程,必须等到 t1、t2 都执行完才会退出 JVM

t1 是非守护线程,t2 是守护线程
@Slf4j
public class Test16 {public static void main(String[] args) throws Exception {Thread t1 = new Thread(() -> {for (int i = 1; i <= 10; i++) {log.info("t1 => " + i);}}, "t1");Thread t2 = new Thread(() -> {for (int i = 1; i <= 50; i++) {log.info("t2 => " + i);}}, "t2");t2.setDaemon(true);t1.start();t2.start();}
}

t1 是非守护线程, t2 是守护线程,当  t1 执行完 JVM 中不存在非守护线程,即使 t2 未执行完,也会退出 JVM

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

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

相关文章

【Hadoop|MapReduce篇】MapReduce概述

1. MapReduce定义 MapReduce是一个分布式运算程序的编程框架&#xff0c;是用户开发“基于Hadoop的数据分析应用”的核心框架。 MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序&#xff0c;并发运行在一个Hadoop集群上。 2. Map…

【绿盟科技盟管家-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

linux 最简单配置免密登录

需求&#xff1a;两台服务器互信登录需要拉起对端服务 ip&#xff1a; 192.168.1.133 192.168.1.137 一、配置主机hosts&#xff0c;IP及主机名&#xff0c;两台都需要 二、192.168.1.137服务器&#xff0c;生成密钥 ssh-keygen -t rsa三、追加到文件 ~/.ssh/authorized_key…

2024年第二届《英语世界》杯全国大学生英语听力大赛

下周开考&#xff01; 一、主办单位 商务印书馆《英语世界》杂志社 二、时间安排 赛事报名时间&#xff1a;即日起-2024年11月15日 正式比赛阶段&#xff1a;第一场&#xff1a;2024年9月22日10:00-22:00 第二场&#xff1a;2024年10月27日10:00-22:00 第三场&#xff1…

QT::QComboBox自定义左击事件信号

因为QComboBox没有自定义的clink信号&#xff0c;所以自己新建一个MyComBox类继承QComboBox&#xff0c;并且添加自定义的左击信号&#xff0c;以及使用该信号连接一个槽函数 mycombobox.h #ifndef MYCOMBOBOX_H #define MYCOMBOBOX_H#include <QComboBox> #include &l…

Baumer工业相机堡盟工业相机如何通过BGAPI SDK设置相机的图像剪切(ROI)功能(C语言)

Baumer工业相机堡盟工业相机如何通过BGAPI SDK设置相机的图像剪切&#xff08;ROI&#xff09;功能&#xff08;C语言&#xff09; Baumer工业相机Baumer工业相机的图像剪切&#xff08;ROI&#xff09;功能的技术背景CameraExplorer如何使用图像剪切&#xff08;ROI&#xff0…

复旦:EoT下Muti-agentllm曾带给我的启发

结合最近的一些经历&#xff0c;回忆起很早之前探索Agent时阅读过的一篇自来复旦/NUS/上海AI Lab的泛CoT框架思想论文&#xff0c;文中提出了一种名为“思想交换”&#xff08;Exchange-of-Thought, EoT&#xff09;的新框架&#xff0c;该框架允许在问题解决过程中进行跨模型交…

android 老项目中用到的jar包不存在,通过离线的方法加载

1、之前的项目用的jar包&#xff0c;已经不在远程仓库中&#xff0c;只能手工去下载&#xff0c;并且安装。 // implementation com.github.nostra13:Android-Universal-Image-Loader // implementation com.github.lecho:hellocharts-android:v1.5.8 这…

信息安全工程师(1)计算机网络分类

一、按分布范围分类 广域网&#xff08;WAN&#xff09;&#xff1a; 定义&#xff1a;广域网的任务是提供长距离通信&#xff0c;运送主机所发送的数据。其覆盖范围通常是直径为几十千米到几千千米的区域&#xff0c;因此也被称为远程网。特点&#xff1a;连接广域网的各个结点…

智能语音技术在人机交互中的应用与发展

摘要&#xff1a;本文主要探讨智能自动语音识别技术与语音合成技术在构建智能口语系统方面的作用。这两项技术实现了人机语音通信&#xff0c;建立起能听能说的智能口语系统。同时&#xff0c;引入开源 AI 智能名片小程序&#xff0c;分析其在智能语音技术应用场景下的意义与发…

实现CPU压力测试工具的C语言实现

实现CPU压力测试工具的C语言实现 一、背景与需求二、伪代码设计三、C语言实现四、编译和运行五、注意事项在软件开发和系统维护中,CPU压力测试是一项重要任务,用于评估系统的稳定性和性能。本篇文章将详细介绍如何使用C语言结合伪代码实现一个简单的CPU压力测试工具。 一、…

软媒市场新趋势:自助发布与一手资源渠道商自助发稿的崛起

在当今这个信息爆炸的时代,软媒市场作为品牌传播的重要阵地,正经历着前所未有的变革。随着技术的不断进步和消费者行为的日益多样化,传统的营销方式已难以满足企业的需求。在这样的背景下,自助发布与一手资源渠道商自助发稿的模式应运而生,为企业的品牌宣传开辟了新的道路。 自…

旺店通ERP集成用友BIP(旺店通主供应链)

源系统成集云目标系统 用友BIP介绍 用友BIP是以数智底座以及财务、人力、供应链、营销、采购、制造、研发、项目、资产、协同等数智化服务成就的数智平台&#xff0c;同时也预置了很多跨行业通用的SaaS服务&#xff0c;在营销、采购、制造、财务、人力、协同等核心业务领域提供…

Wophp靶场漏洞挖掘

首先进入网站发现有个搜索框&#xff0c;那么我们试一下xss和SQL注入 SQL注入漏洞 发现这里页面没有给我们回显 那么我们尝试sql注入 查数据库 查表 最后查出账号密码 找到账号密码之后我们去找后台登录 进入后台后发现这里有个flag flag 接着往下翻找到一个文件上传的地方 …

linux-L3-linux 复制文件

linux 中要将文件file1.txt复制到目录dir中&#xff0c;可以使用以下命令 cp file1.txt dir/复制文件 cp /path/to/source/file /path/to/destination移动 mv /path/to/source/file /path/to/destination复制文件夹内的文件 cp -a /path/to/source/file /path/to/destinati…

2024年开学季,有哪些大学宿舍必备好物?

随着2024年开学季的到来&#xff0c;新生们即将离开熟悉的家乡&#xff0c;踏入充满未知与挑战的大学生活。对于许多学子而言&#xff0c;宿舍不仅是他们未来几年的居住之所&#xff0c;更是承载青春记忆、实现自我成长的重要空间。为了帮助大家更好地适应校园生活&#xff0c;…

JavaScript高级——变量提升和函数提升

1、变量声明提升 —— 通过 var 定义&#xff08;声明&#xff09;的变量&#xff0c;在定义语句之前就可以访问到 —— 值&#xff1a;undefined 2、函数声明提升 —— 通过 function 声明的函数&#xff0c;在之前就可以直接调用 —— 值&#xff1a;函数定义&#xff0…

【PythonCode】力扣Leetcode41~45题Python版

【PythonCode】力扣Leetcode41~45题Python版 前言 力扣Leetcode是一个集学习、刷题、竞赛等功能于一体的编程学习平台&#xff0c;很多计算机相关专业的学生、编程自学者、IT从业者在上面学习和刷题。 在Leetcode上刷题&#xff0c;可以选择各种主流的编程语言&#xff0c;如C…

关于Redis缓存一致性问题的优化和实践

目录标题 导语正文分布式场景下无法做到强一致即使是达到最终一致性也很难缓存的一致性问题缓存是如何写入的 如何感知数据库的变化最佳实践一&#xff1a;数据库变更后失效缓存最佳实践二&#xff1a;带版本写入 总结与展望阿里XKV腾讯DCache 导语 Redis缓存一致性的问题是经…

023.PL-SQL进阶—视图

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…