Java多线程
目录
- 1 多线程
- 1.1 进程
- 1.2 线程
- 1.3 多线程的实现方式
- 1.3.1 方式1:继承Tread类
- 1.3.2 方式2:实现Runnable接口
- 1.3.3 方式3:实现Callable接口
- 1.4 设置和获取线程名称
- 1.5 线程调度
- 1.6 线程控制
- 1.7 线程生命周期
- 1.8 数据安全问题之案例:买票
- 1.9 线程同步_同步代码块
- 1.10 线程同步_同步方法
- 1.11 线程安全的类(了解)
- 1.12 Lock锁
- 1.13 线程通讯
- 1.14 生产者消费者
- 1.14.1 生产者消费者概述
- 1.14.2 生产者消费者案例
1 多线程
1.1 进程
- 进程:是正在运行的程序
- 是系统进行资源分配和调用的独立单位
- 每一个进行都有它自己的内存空间和系统资源
- 进程的三个特征
- 独立性:进程与进程之间是相互独立的,彼此有自己独立内存区域
- 动态性:进程是运行中的程序,要动态的占用内存,CPU和网络等资源
- 并发性:CPU会分时轮询切换依次为每个进程服务,因为切换的速度非常快,给我们的感觉像是在同时执行,这就是并发性(并发:同一时刻同时有多个在执行)
1.2 线程
- 线程:是进程中的单个顺序控制流,是一条执行路径
- 单线程:一个进程只有一条执行路径
- 多线程:一个进程有多条执行路径
1.3 多线程的实现方式
1.3.1 方式1:继承Tread类
-
流程:
- 1、定义一个MyTread类继承Tread类
- 2、在MyTread类中重写
run()
方法 - 3、创建MyTread类的对象
- 4、启动线程:
void start()
-
为什么要重写run()方法?
- 因为run()是用来封装被线程执行的代码
-
run()方法和start()方法的区别?
- run():封装线程执行的代码,直接调用,相当于普通方法的的调用
- start():启动线程,然后由JVM调用此线程中的run()方法
-
范例
-
MyTread类:
package test;//1、定义一类MyTread继承Tread类
public class MyThread extends Thread{2、在MyTread类中重写run()方法@Overridepublic void run() {for(int i=0;i<100;i++) {System.out.println(i);}}
}
- 测试类
package test;public class Demo {public static void main(String[] args) {//3、创建MyTread类的对象MyThread my1 = new MyThread();MyThread my2 = new MyThread();//4、启动线程:void start():启动线程,由Java虚拟机调用此线程的run()方法my1.start();my2.start();}
}
1.3.2 方式2:实现Runnable接口
- 流程:
- 1、定义一个MyRunnable类实现Runnable接口
- 2、在MyRunnable类中重写
run()
方法 - 3、创建MyRunnable类的对象
- 4、创建Tread类的对象,把MyRunnable对象作为构造方法的参数
- 5、启动线程
- 好处:
- 避免了Java单继承的局限性
- 适合多个相同程序的代码取处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好地体现了面向对象的设计理论
package test;public class Demo {public static void main(String[] args) {//3、创建MyRunnable类的对象MyRunnable mr = new MyRunnable();//4、创建Tread类的对象,把MyRunnable对象作为构造方法的参数
// Thread t1 = new Thread(mr);
// Thread t2 = new Thread(mr);//Thread(Runnable target,String name)Thread t1 = new Thread(mr,"高铁");Thread t2 = new Thread(mr,"飞机");//5、启动线程t1.start();t2.start();}
}
1.3.3 方式3:实现Callable接口
1.4 设置和获取线程名称
- Thread类中设置和获取线程名称的方法
方法名 | 说明 |
---|---|
void setName(Stringname) | 将此线程的名称更改为等于参数name |
String getName() | 返回此线程的名称 |
public Thread(String name) | 通过构造方法也可以设置线程名称 |
public static Thread currentThread() | 返回对当前正在执行的线程对象的引用(可以返回main()方法中线程) |
public static void sleep(long time) | 让当前线程休眠多少毫秒再继续执行 |
- MyThread类
package test;public class MyThread extends Thread{//构造方法添加线程名称public MyThread(){}public MyThread(String name) {super(name);}@Overridepublic void run() {for(int i=0;i<100;i++) {//1,String getName() 返回此线程的名称System.out.println(getName()+":"+i);}}
}
- 测试类
package test;public class Demo {public static void main(String[] args) {/* MyThread my1 = new MyThread();MyThread my2 = new MyThread();//2,void setName(Stringname) 将此线程的名称更改为等于参数namemy1.setName("高铁");my2.setName("飞机");*///3,通过构造方法设置线程名称//需要自己定义的类中提供此带参构造方法,并通过super访问父类带参构造方法/*MyThread my1 = new MyThread("高铁");MyThread my2 = new MyThread("飞机"); my1.start();my2.start();*///4,public static Thread currentThread() 返回对当前正在执行的线程对象的引用(可以返回main()方法中线程)System.out.println(Tread.currentThread().getName()); //main}
}
1.5 线程调度
-
线程有两种调度模型
- 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
- 抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些
-
Java使用的是抢占式调度模型
-
假如计算机只有一个CPU, 那么CPU在某一个时刻只能执行条指令, 线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的
-
Thread类中设置和获取线程优先级的方法
方法名 | 说明 |
---|---|
public final int getPriority() [praɪˈɔːrəti] | 返回此线程的优先级 |
public final void setPriority(int newPriority) | 更改此线程的优先级 |
- 线程默认优先级是5;线程优先级范围是:1-10
- 线程优先级高仅仅表示线程获取的CPU时间的几率高,但是要在次数比较多,或者多次运行的时候才能看到你想要的效果
package test;public class Demo {public static void main(String[] args) {ThreadPriority tp1 = new ThreadPriority();ThreadPriority tp2 = new ThreadPriority();ThreadPriority tp3 = new ThreadPriority();tp1.setName("高铁");tp2.setName("飞机");tp3.setName("汽车");//1,public final int getPriority() [praɪˈɔːrəti] 返回此线程的优先级
// System.out.println(tp1.getPriority()); //5
// System.out.println(tp2.getPriority()); //5
// System.out.println(tp3.getPriority()); //5//2,public final void setPriority(int newPriority) 更改此线程的优先级System.out.println(Thread.MAX_PRIORITY); //10System.out.println(Thread.MIN_PRIORITY); //1System.out.println(Thread.NORM_PRIORITY); //5//设置正确优先级tp1.setPriority(5);tp2.setPriority(10);tp3.setPriority(1);tp1.start();tp2.start();tp3.start();}
}
1.6 线程控制
方法名 | 说明 |
---|---|
static void sleep(long millis) | 使当前正在执行的线程停留(暂停执行)指定的毫秒数 |
void join() | 等待这个线程死亡 |
void setDaemon(boolean on) [ˈdiːmən] | 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机很快将退出 (并不是立刻退出) |
案例:sleep()方法
- 线程类
package test;public class ThreadSleep extends Thread{@Overridepublic void run() {for(int i=0;i<10;i++) {System.out.println(getName()+":"+i);//1,static void sleep(long millis) 使当前正在执行的线程停留(暂停执行)指定的毫秒数try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
- 测试类
package test;public class Demo {public static void main(String[] args) {ThreadSleep ts1 = new ThreadSleep();ThreadSleep ts2 = new ThreadSleep();ThreadSleep ts3 = new ThreadSleep();ts1.setName("曹操");ts2.setName("刘备");ts3.setName("孙权");ts1.start();ts2.start();ts3.start();// 曹操:0
// 孙权:0
// 刘备:0
// 孙权:1
// 曹操:1
// 刘备:1
// ...}
}
案例:join()方法
package test;public class Demo {public static void main(String[] args) {ThreadJoin tj1 = new ThreadJoin();ThreadJoin tj2 = new ThreadJoin();ThreadJoin tj3 = new ThreadJoin();tj1.setName("康熙");tj2.setName("四阿哥");tj3.setName("八阿哥");tj1.start();//2,void join() 等待这个线程死亡try {tj1.join();} catch (InterruptedException e) {e.printStackTrace();}tj2.start();tj3.start();// 康熙:0
// 康熙:1
// 康熙:2
// 四阿哥:0
// 四阿哥:1
// 八阿哥:0
// 八阿哥:1
// 八阿哥:2
// 四阿哥:2
// ...}
}
案例:setDaemon()方法
package test;public class Demo {public static void main(String[] args) {ThreadJoin tj1 = new ThreadJoin();ThreadJoin tj2 = new ThreadJoin();ThreadJoin tj3 = new ThreadJoin();tj2.setName("关羽");tj3.setName("张飞");//设置主线程为刘备Thread.currentThread().setName("刘备");//3,void setDaemon(boolean on) 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出tj1.setDaemon(true);tj2.setDaemon(true);tj1.start();tj2.start();for(int i=0;i<2;i++) {System.out.println(Thread.currentThread().getName()+":"+i);}//刘备执行完后,关羽和张飞会很快结束}
}
1.7 线程生命周期
1.8 数据安全问题之案例:买票
-
为什么出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准)
- 是否是多线程环境
- 是否有共享数据
- 是否有多条语句操作共享数据
-
如何解决多线程安全问题呢?
-
基本思想:让程序没有安全问题的环境
-
怎么实现呢?
- 把多条语句操作共享 数据的代码给锁起来,让任意时刻只能有一一个线程执行即可
- Java提供 了同步代码块的方式来解决
1.9 线程同步_同步代码块
- 锁多条语句操作共享数据,可以使用同步代码块实现
- 格式
synchronized(任意对象) {多条语句操作共享数据的代码
}
-
好处:让多个线程实现先后依次访问共享资源,解决了多线程的数据安全问题
-
弊端:当线程很多的时候,因为每个线程都会去判断同步上的锁,这是很消耗资源的,无形中降低程序的运行效率
-
sellTicket类
package test;//1,定义一个类SellTicket实现Runnable接口,里面定义一个成员变量: private int tickets= 100;
public class SellTicket implements Runnable{private int tickets = 100;private Object obj = new Object();//2,在ellTicket类中重写run0方法实现卖票, 代码步骤如下@Overridepublic void run() {while(true) {//tickes=100//t1,t2,t3//假设t1抢到CPU执行器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出来了,锁就被释放了}}}
}
- 测试类
package test;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();}
}
1.10 线程同步_同步方法
- 作用:把出现线程安全问题的核心方法给锁起来,每次只能一个线程进入访问,其他线程必须在方法外面等待
- 同步方法:就是把synchronized关键字加到方法上;锁对象为:
this
- 格式:
修饰符 synchronized 返回值类型 方法名(方法参数) {}
- 格式:
- 同步静态方法:就是把synchronized关键字加到静态方法上面;锁对象为:
类名.class
- 格式:
修饰符 static synchronized 返回值类型 方法名(方法参数) {}
- 格式:
package test;public class SellTicket implements Runnable{
//1非静态 private int tickets = 100;private static int tickets = 100;private Object obj = new Object();private int x = 0;@Overridepublic void run() {while(true) {if(x%2==0) {
//1非静态 synchronized (this) {synchronized (SellTicket.class) {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");tickets--; //tickets=99}}} else {
// synchronized (obj) {
// if (tickets > 0) {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
// tickets--; //tickets=99
// }
// }sellTicket();}x++;}}
//1非静态
// private synchronized void sellTicket() {
// if (tickets > 0) {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
// tickets--; //tickets=99
// }
// }private static synchronized void sellTicket() {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");tickets--; //tickets=99}}
}
1.11 线程安全的类(了解)
源码中方法都被synchronized修饰
StringBuffer
- 线程安全, 可变的字符序列
- 从版本JDK 5开始,被StringBuilder替代。通常应该使用StringBuilder类, 因为它支持所有相同的操作,但它更快,因为它不执行同步
Vector
- 从Java 2平台v1.2开始,该类改进了List接口, 使其成为Java Collections Framework的成员。 与新的集合实现不同,Vector被同步。 如果不需要线程安全的实现,建议使用ArrayList代替Vector
Hashtable
- 该类实现了一个哈希表,它将键映射到值。任何非null对象都可以用作键或者值
- 从Java 2平台v1.2开始,该类进行了改进,实现了Map接口,使其成为Java Collections Framework的成员。与新的集合实现不同,Hashtable被同步。 如果不需要线程安全的实现,建议使用HashMap代替Hashtable
Collections
类中static <T> List<T> snchronizedList(List<T> list)
:返回由指定列表支持的同步(线程安全)的列表
package test;import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;public class Demo {public static void main(String[] args) {//static <T> List<T> snchronizedList(List<T> list):返回由指定列表支持的同步(线程安全)的列表Collection<String> list = Collections.synchronizedList(new ArrayList<String>());/*源码都是返回Synchronizedpublic static <T> List<T> synchronizedList(List<T> list) {return (list instanceof RandomAccess ?new Collections.SynchronizedRandomAccessList<>(list) :new Collections.SynchronizedList<>(list));}*/}
}
1.12 Lock锁
- Lock是接口不能直接实例化,采用实现类ReentrantLock来实例化(JDK5以后)
- ReentrantLock构造方法:
方法名 | 说明 |
---|---|
ReentrantLock() | 创建一个ReentrantLock的实例对象 |
- Lock中获得锁和释放锁方法:
方法名 | 说明 |
---|---|
void lock() | 获得锁 |
void unlock() | 释放锁 |
- 推荐使用
try{} finall{}
代码块来加锁和释放锁
package test;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class SellTicket implements Runnable{private static int tickets = 100;private Lock lock = new ReentrantLock();@Overridepublic void run() {while(true) {try {lock.lock();if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");tickets--;}}finally {lock.unlock();}}}
}
1.13 线程通讯
- 线程通信一定是多个线程在操作同一个资源才需要通信
方法名 | 说明 |
---|---|
public void wait() | 让当前线程进入到等待状态,此方法必须锁对象调用 |
public void notify() | 唤醒当前锁对象上等待状态的某个线程,此方法必须锁对象调用 |
public void notifyAll() | 唤醒当前锁对象上等待状态的全部线程,此方法必须锁对象调用 |
1.14 生产者消费者
1.14.1 生产者消费者概述
- 为了体现生产和消费过程中的等待和唤醒,Java就提供了几个方法供我们使用,这几个方法在Object类中
- Object类的等待和唤醒方法
方法名 | 说明 |
---|---|
void wait() | 导致当前线程等待,直到另一个线程调用该对象的 notify() 方法或 notifyAll() 方法 |
void notify() | 唤醒正在等待对象监视器的单个线程 |
void notifyAll() | 唤醒正在等待对象监视器的所有线程 |
1.14.2 生产者消费者案例
- 奶箱类
package test;//1:定义奶箱类
public class Box {//定义一个成员变量,表示第x瓶奶private int milk;//定义一个成员变量表示奶箱的状态private boolean state = false;//提供存储牛奶和获取牛奶的操作public synchronized void put(int milk) {//如果有牛奶等待消费if(state) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果没有牛奶,就生产牛奶this.milk = milk;System.out.println("送奶工将第" + this.milk + "瓶奶放入奶箱");//生产完毕后,修改奶箱状态state = true;//唤醒其他等待线程notifyAll();}public synchronized void get() {//如果没有牛奶,就等到生产if(!state) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果有牛奶,就消费牛奶System.out.println("用户拿到第" + this.milk + "瓶奶");//消费完毕后,修改奶箱状态state = false;//唤醒其他等待线程notifyAll();}
}
- 生产者类
package test;//2:生产者类(Producer):实现Runnable接口
public class Producer implements Runnable {private Box b;public Producer(Box b) {this.b = b;}//重写run()方法,调用存储牛奶的操作@Overridepublic void run() {for (int i = 1; i <= 5; i++) {b.put(i);}}
}
- 消费者类
package test;//3:消费者类(Customer);实现Runnable接口
public class Customer implements Runnable{private Box b;public Customer(Box b) {this.b = b;}//重写run()方法,调用获取牛奶的操作@Overridepublic void run() {while(true) {b.get();}}
}
- 测试类
package test;public class BoxDemo {public static void main(String[] args) {//创建奶箱对象,这是共享数据区域Box b = new Box();//创建生产者对象,把奶箱对象作为构造方法参数传递。因为在这个类中要谓用存储牛奶的操作Producer p = new Producer(b);//创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作Customer c =new Customer(b);//创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递Thread t1 = new Thread(p);Thread t2 = new Thread(c);//启动线程t1.start();t2.start();// 送奶工将第1瓶奶放入奶箱
// 用户拿到第1瓶奶
// 送奶工将第2瓶奶放入奶箱
// 用户拿到第2瓶奶
// 送奶工将第3瓶奶放入奶箱
// 用户拿到第3瓶奶
// 送奶工将第4瓶奶放入奶箱
// 用户拿到第4瓶奶
// 送奶工将第5瓶奶放入奶箱
// 用户拿到第5瓶奶}
}
相关文章:

Java多线程
目录1 多线程1.1 进程1.2 线程1.3 多线程的实现方式1.3.1 方式1:继承Tread类1.3.2 方式2:实现Runnable接口1.3.3 方式3:实现Callable接口1.4 设置和获取线程名称1.5 线程调度1.6 线程控制1.7 线程生命周期1.8 数据安全问题之案例:…...

linux高级命令之线程执行带有参数的任务
线程执行带有参数的任务学习目标能够写出线程执行带有参数的任务1. 线程执行带有参数的任务的介绍前面我们使用线程执行的任务是没有参数的,假如我们使用线程执行的任务带有参数,如何给函数传参呢?Thread类执行任务并给任务传参数有两种方式:args 表示以…...

管理会计报告和财务报告的区别
财务会计报告是给投资人看的,可以反映公司总体的盈利能力。不过,我们回顾一下前面“第一天”里面提到的问题。如果你是公司的产品经理,目前有三个产品在你的管辖范围内。上级给你一笔新的资金,这笔资金应该投到哪个产品上…...
华为OD机试 - 最左侧冗余覆盖子串(Python) | 机试题算法思路 【2023】
最近更新的博客 华为OD机试 - 自动曝光(Python) | 机试题算法思路 【2023】 华为OD机试 - 双十一(Python) | 机试题算法思路 【2023】 华为OD机试 - 删除最少字符(Python) | 机试题算法思路 【2023-02】 华为OD机试 - Excel 单元格数值统计(Python) | 机试题算法思路 …...

【Opencv 系列】第1章 图像基础
通过本套课程,可以学到: 1.opencv的基本操作 2.两个案例,目标追踪&人脸识别 对重点内容,我会提示,包括我再准备这套课程过程中遇到的坑点! 最后代码我会放到git上,章节顺序一致:https://github.com/justinge/opencv_tutorial.git 系列文章目录 第1章 Opencv 图像基础 和 …...
创建和销毁对象——遇到多个构造器参数时要考虑使用构建器
静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。比如用一个类表示包装食品外面显示的营养成分标签。这些标签中有几个域是必需的:每份的含量、每罐的含量以及每份的卡路里。还有超过20个的可选域:总脂肪量、饱和脂…...

【c++学习】入门c++(中)
目录一. 前言二. 函数重载1. 概念2.函数名修饰规则三 .引用(&)1. 概念2. 引用特性3.应用1.做参数2. 做返回值3. 传值、传引用效率比较4.引用和指针的区别四 . 结语一. 前言 小伙伴们大家好,今天我们继续学习c入门知识,今天的…...

论文阅读_AlphaGo_Zero
论文信息 name_en: Mastering the game of Go without human knowledge name_ch: 在没有人类知识的情况下掌握围棋游戏 paper_addr: http://www.nature.com/articles/nature24270 doi: 10.1038/nature24270 date_publish: 2017-10-01 tags: [‘深度学习’,‘强化学习’] if: 6…...
一文教你用Python创建自己的装饰器
python装饰器在平常的python编程中用到的还是很多的,在本篇文章中我们先来介绍一下python中最常使用的staticmethod装饰器的使用。 目录一、staticmethod二、自定义装饰器python类实现装饰器python函数嵌套实现装饰器多个装饰器调用三、带参数的装饰器一、staticmet…...
华为OD机试 - 任务总执行时长(JS)
任务总执行时长 题目 任务编排服务负责对任务进行组合调度。参与编排的任务又两种类型,其中一种执行时长为taskA,另一种执行时长为taskB。任务一旦开始执行不能被打断,且任务可连续执行。服务每次可以编排num个任务。 请编写一个方法,生成每次编排后的任务所有可能的总执…...

pytorch离线快速安装
1.pytorch官网查看cuda版本对应的torch和torchvisionde 版本(ncvv -V,nvidia-sim查看cuda对应的版本) 2.离线下载对应版本,网址https://download.pytorch.org/whl/torch_stable.html 我下载的: cu113/torch-1.12.0%2Bcu113-cp37-cp37m-win_…...
华为OD机试 - 数组合并(JS)
数组合并 题目 现在有多组整数数组,需要将他们合并成一个新的数组。 合并规则,从每个数组里按顺序取出固定长度的内容合并到新的数组中, 取完的内容会删除掉, 如果该行不足固定长度或者已经为空, 则直接取出剩余部分的内容放到新的数组中,继续下一行。 如样例1,获得长度3,先遍…...

不要让GPT成为你通向“学业作弊”的捷径——使用GPT检测工具来帮助你保持正确的方向
不要让GPT成为你通向“学业作弊”的捷径——使用GPT检测工具来帮助你保持正确的方向 最近,多所美国高校以及香港大学等都明确禁止在校使用ChatGPT等智能文本生成工具。GPT(Generative Pre-trained Transformer)是一种自然语言处理技术&#x…...

基于matlab的斜视模式下SAR建模
一、前言此示例说明如何使用线性 FM (LFM) 波形对基于聚光灯的合成孔径雷达 (SAR) 系统进行建模。在斜视模式下,SAR平台根据需要从宽侧斜视一定角度向前或向后看。斜视模式有助于对位于当前雷达平台位置前面的区域进行…...

15-基础加强-1-类加载器反射
文章目录1.类加载器1.1类加载器【理解】1.2类加载的过程【理解】1.3类加载的分类【理解】1.4双亲委派模型【理解】1.5ClassLoader 中的两个方法【应用】2.反射2.1反射的概述【理解】2.2获取Class类对象的三种方式【应用】 第1步:获取类的Class对象2.3反射获取构造方…...

基于SSM,Spring, BootStrap 毕业设计管理系统的设计与实现
目录 一.前言介绍 二、主要技术 2.1 SSM框架介绍 2.2 MYSQL数据库 2.3 持久层框架MyBatis 2.4 前端框架BootStrap 三. 系统设计 3.1 系统架构设计 3.2 系统功能模块 3.2.1 学生模块 3.2.2 教师模块 3.2.3 管理员模块 四、数据库设计 4.1 数据分析 4.2 概念设计 …...

一招鉴别真假ChatGPT,并简要介绍ChatGPT、GPT、GPT2和GPT3模型之间的区别和联系
以下内容除红色字体部分之外,其他均来源于ChatGPT自动撰写。 ChatGPT是基于GPT模型的对话生成模型,旨在通过对话模拟实现自然语言交互。它是为了改善人机对话体验而设计的,主要应用于聊天机器人、智能客服等场景。 与GPT模型相比,…...
华为OD机试 - 特异性双端队列(JS)
特异性双端队列 题目 有一个特异性的双端队列,该队列可以从头部到尾部添加数据,但是只能从头部移除数据。 小A一次执行 2n 个指令往队列中添加数据和移除数据, 其中 n 个指令是添加数据(可能从头部也可以从尾部添加) 依次添加 1 到 n , n 个指令是移出数据 现在要求移除数…...
Nginx自动封禁可疑Ip
文章目录一、Nginx封禁ip1、简介2、nignx 禁止IP访问2.1 方法一2.2 方法二3、关于 deny 的使用二、脚本自动封禁Ip1、流程介绍2、脚本实战2.1 核心脚本解释2.2 编写shell脚本2.3 crontab定时一、Nginx封禁ip 1、简介 在网站维护过程中,有时候我们需要对一些IP地址…...

分布式事务--理论基础
1、事务基础 1.1、什么是事务 事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败。 1.2、本地事务 在同一个进程内,控制同一数据源的事务,称为本地事务。例如数据库事务。 在计…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...

C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...

Selenium 查找页面元素的方式
Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素,以下是主要的定位方式: 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...
【Java】Ajax 技术详解
文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…...
C#最佳实践:为何优先使用as或is而非强制转换
C#最佳实践:为何优先使用as或is而非强制转换 在 C# 的编程世界里,类型转换是我们经常会遇到的操作。就像在现实生活中,我们可能需要把不同形状的物品重新整理归类一样,在代码里,我们也常常需要将一个数据类型转换为另…...