day12 多线程
目录
1.概念相关
1.1什么是线程
1.2什么是多线程
2.创建线程
2.1方式一:继承Thread类
2.1.1实现步骤
2.1.2优缺点
2.1.3注意事项
2.2方式二:实现Runnable接口
2.2.1实现步骤
2.2.2优缺点
2.2.3匿名内部类写法
2.3方式三:实现callable接口
2.3.1callable接口解决了什么问题
2.3.2实现步骤
2.3.3FutureTask的API
2.3.4优缺点
3.线程的常用方法
4.线程安全
4.1什么是线程安全
4.2线程安全问题出现的原因
4.3模拟线程安全问题场景 :取钱
5.线程同步
5.1什么是线程同步
5.2线程同步的核心思想
5.3常见方案
5.4方式一:同步代码块
5.4.1作用:
5.4.2原理:
5.4.3注意事项:
5.4.4锁对象的使用规范
5.4.5如何实现线程安全的
5.5方式二:同步方法
5.5.1作用
5.5.2原理
5.5.3底层原理
5.5.4同步代码块和同步方法哪种好
5.6lock锁
5.6.1lock锁是什么
5.6.2lock锁的构造器、常用方法
5.6.3锁对象建议加上什么修饰
5.6.4释放锁的操作建议放到哪里
6.线程池
6.1认识线程池
6.2不使用线程池的后果
6.3创建线程池
6.4任务拒绝策略
6.5线程池的注意事项
6.6处理runnable任务
6.4.1ExecutorService的常用方法
6.7处理callable
6.8通过Executors创建线程池
6.8.1方法
6.8.2Executors使用可能存在的陷阱
7.并发、并行
7.1进程
7.2并发的含义
7.3并行的含义
1.概念相关
1.1什么是线程
线程(Thread)是一个程序内部的一条执行流程。程序中如果只有一条执行流程,那这个程序就是单线程的程序。
1.2什么是多线程
多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)。
2.创建线程
2.1方式一:继承Thread类
2.1.1实现步骤
【1】定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
【2】创建MyThread类的对象
【3】调用线程对象的start()方法启动线程(启动后还是执行run方法的)
2.1.2优缺点
【1】优点:编码简单
【2】缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。
2.1.3注意事项
【1】启动线程必须是调用start方法,不是调用run方法。
【2】不要把主线程任务放在启动子线程之前。
public class Test {public static void main(String[] args) {Thread t1=new MyThread();t1.start();for (int i = 0; i < 5; i++) {System.out.println("主线程"+i);}}}class MyThread extends Thread{@Overridepublic void run(){for (int i = 0; i < 10; i++){System.out.println("子线程" + i);}}
}
2.2方式二:实现Runnable接口
2.2.1实现步骤
【1】定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
【2】创建MyRunnable任务对象
【3】把MyRunnable任务对象交给Thread处理。
【4】调用线程对象的start()方法启动线程
2.2.2优缺点
【1】优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。
【2】缺点:需要多一个Runnable对象。
2.2.3匿名内部类写法
【1】可以创建Runnable的匿名内部类对象。
【2】再交给Thread线程对象。
【3】再调用线程对象的start()启动线程。
public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程"+i);}}}).start();new Thread(()->{for (int i = 0; i < 5; i++) {System.out.println("子线程2"+i);}}).start();for (int i = 0; i < 5; i++) {System.out.println("主线程"+i);}}
2.3方式三:实现callable接口
2.3.1callable接口解决了什么问题
假如线程执行完毕后有一些数据需要返回,前两种重写的run方法均不能直接返回结果。使用Callable接口和FutureTask类来实现创建,可以返回线程执行完毕后的结果。
2.3.2实现步骤
【1】定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据。
【2】把Callable类型的对象封装成FutureTask(线程任务对象)。
【3】把线程任务对象交给Thread对象。
【4】调用Thread对象的start方法启动线程。
【5】线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果。
2.3.3FutureTask的API
FutureTask提供的构造器 | 说明 |
public FutureTask<>(Callable call) | 把Callable对象封装成FutureTask对象。 |
FutureTask提供的方法 | 说明 |
public V get() throws Exception | 获取线程执行call方法返回的结果。 |
2.3.4优缺点
【1】优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果。
【2】缺点:编码复杂一点。
public class ThreadDemo3 {public static void main(String[] args) {// 目标:掌握多线程的创建方式三:实现Callable接口,方式三的优势:可以获取线程执行完毕后的结果的。// 3、创建一个Callable接口的实现类对象。Callable<String> c1 = new MyCallable(100);// 4、把Callable对象封装成一个真正的线程任务对象FutureTask对象。/*** 未来任务对象的作用?* a、本质是一个Runnable线程任务对象,可以交给Thread线程对象处理。* b、可以获取线程执行完毕后的结果。*/FutureTask<String> f1 = new FutureTask<>(c1); // public FutureTask(Callable<V> callable)// 5、把FutureTask对象作为参数传递给Thread线程对象。Thread t1 = new Thread(f1);// 6、启动线程。t1.start();Callable<String> c2 = new MyCallable(50);FutureTask<String> f2 = new FutureTask<>(c2); // public FutureTask(Callable<V> callable)Thread t2 = new Thread(f2);t2.start();// 获取线程执行完毕后返回的结果try {// 如果主线程发现第一个线程还没有执行完毕,会让出CPU,等第一个线程执行完毕后,才会往下执行!System.out.println(f1.get());} catch (Exception e) {e.printStackTrace();}try {// 如果主线程发现第二个线程还没有执行完毕,会让出CPU,等第一个线程执行完毕后,才会往下执行!System.out.println(f2.get());} catch (Exception e) {e.printStackTrace();}}
}// 1、定义一个实现类实现Callable接口
class MyCallable implements Callable<String> {private int n;public MyCallable(int n) {this.n = n;}// 2、实现call方法,定义线程执行体public String call() throws Exception {int sum = 0;for (int i = 1; i <= n; i++) {sum += i;}return "子线程计算1-" + n + "的和是:" + sum;}
}
3.线程的常用方法
Tread提供的常用方法 | 说明 |
public void run() | 线程的任务方法 |
public void start() | 启动线程 |
public String getName() | 获取当前线程的名称,线程名称默认是Thread-索引 |
public void setName(String name) | 为线程设置名称 |
public static Thread currentThread() | 获取当前执行的线程对象 |
public static void sleep(long time) | 让当前执行的线程休眠多少毫秒后,再继续执行 |
public final void join()... | 让调用当前这个方法的线程先执行完! |
public class ThreadApiDemo1 {public static void main(String[] args) {// 目标:搞清楚线程的常用方法。Thread t1 = new MyThread("1号线程");// t1.setName("1号线程");t1.start();System.out.println(t1.getName()); // 线程默认名称是:Thread-索引Thread t2 = new MyThread("2号线程");// t2.setName("2号线程");t2.start();System.out.println(t2.getName()); // 线程默认名称是:Thread-索引// 哪个线程调用这个代码,这个代码就拿到哪个线程Thread m = Thread.currentThread(); // 主线程m.setName("主线程");System.out.println(m.getName()); // main}
}// 1、定义一个子类继承Thread类,成为一个线程类。
class MyThread extends Thread {public MyThread(String name) {super(name); // public Thread(String name)}// 2、重写Thread类的run方法@Overridepublic void run() {// 3、在run方法中编写线程的任务代码(线程要干的活儿)for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() +"子线程输出:" + i);}}
}
public static void main(String[] args) {// 目标:搞清楚Thread类的Sleep方法(线程休眠)for (int i = 1; i <= 10; i++) {System.out.println(i);try {// 让当前执行的线程进入休眠状态,直到时间到了,才会继续执行。// 项目经理让我加上这行代码,如果用户交钱了,我就注释掉。Thread.sleep(1000); // 1000ms = 1s} catch (Exception e) {e.printStackTrace();}}}
public class ThreadApiDemo3 {public static void main(String[] args) {// 目标:搞清楚线程的join方法:线程插队:让调用这个方法线程先执行完毕。MyThread2 t1 = new MyThread2();t1.start();for (int i = 1; i <= 5; i++) {System.out.println(Thread.currentThread().getName() +"线程输出:" + i);if(i == 1){try {t1.join(); // 插队 让t1线程先执行完毕,然后继续执行主线程} catch (Exception e) {e.printStackTrace();}}}}
}class MyThread2 extends Thread {@Overridepublic void run() {for (int i = 1; i <= 5; i++) {System.out.println(Thread.currentThread().getName() +"子线程输出:" + i);}}
}
4.线程安全
4.1什么是线程安全
多个线程,同时操作同一个共享资源的时候,可能会出现业务安全问题。
4.2线程安全问题出现的原因
【1】存在多个线程在同时执行
【2】同时访问一个共享资源
【3】存在修改该共享资源
4.3模拟线程安全问题场景 :取钱
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {private String cardId; // 卡号private double money; // 余额// 小明和小红都到这里来了取钱public synchronized void drawMoney(double money) {// 拿到当前谁来取钱。String name = Thread.currentThread().getName();// 判断余额是否足够if (this.money >= money) {// 余额足够,取钱System.out.println(name + "取钱成功,吐出了" + money + "元成功!");// 更新余额this.money -= money;System.out.println(name + "取钱成功,取钱后,余额剩余" + this.money + "元");} else {// 余额不足System.out.println(name + "取钱失败,余额不足");}}
}
// 取钱线程类
public class DrawThread extends Thread{private Account acc; // 记住线程对象要处理的账户对象。public DrawThread(String name, Account acc) {super(name);this.acc = acc;}@Overridepublic void run() {// 小明 小红 取钱acc.drawMoney(100000);}
}
public static void main(String[] args) {// 目标:模拟线程安全问题。// 1、设计一个账户类:用于创建小明和小红的共同账户对象,存入10万。Account acc = new Account("ICBC-110", 100000);// 2、设计线程类:创建小明和小红两个线程,模拟小明和小红同时去同一个账户取款10万。new DrawThread("小明", acc).start();new DrawThread("小红", acc).start();}
5.线程同步
5.1什么是线程同步
线程同步是线程安全问题的解决方案。
5.2线程同步的核心思想
让多个线程先后依次访问共享资源,这样就可以避免出现线程安全问题。
5.3常见方案
加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来。
5.4方式一:同步代码块
5.4.1作用:
把访问共享资源的核心代码给上锁,以此保证线程安全。
5.4.2原理:
每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
5.4.3注意事项:
对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象),否则会出bug。
5.4.4锁对象的使用规范
【1】建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象。
【2】对于静态方法建议使用字节码(类名.class)对象作为锁对象。
5.4.5如何实现线程安全的
【1】对出现问题的核心代码使用synchronized进行加锁
【2】每次只能一个线程占锁进入访问
// 小明和小红都到这里来了取钱public void drawMoney(double money) {// 拿到当前谁来取钱。String name = Thread.currentThread().getName();// 判断余额是否足够synchronized (this) {if (this.money >= money) {// 余额足够,取钱System.out.println(name + "取钱成功,吐出了" + money + "元成功!");// 更新余额this.money -= money;System.out.println(name + "取钱成功,取钱后,余额剩余" + this.money + "元");} else {// 余额不足System.out.println(name + "取钱失败,余额不足");}}}
5.5方式二:同步方法
5.5.1作用
把访问共享资源的核心方法给上锁,以此保证线程安全。
5.5.2原理
每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行
5.5.3底层原理
【1】同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。
【2】如果方法是实例方法:同步方法默认用this作为的锁对象。
【3】如果方法是静态方法:同步方法默认用类名.class作为的锁对象。
5.5.4同步代码块和同步方法哪种好
同步代码块锁的范围更小,同步方法锁的范围更大。同步方法可读性更好
// 小明和小红都到这里来了取钱public synchronized void drawMoney(double money) {// 拿到当前谁来取钱。String name = Thread.currentThread().getName();// 判断余额是否足够if (this.money >= money) {// 余额足够,取钱System.out.println(name + "取钱成功,吐出了" + money + "元成功!");// 更新余额this.money -= money;System.out.println(name + "取钱成功,取钱后,余额剩余" + this.money + "元");} else {// 余额不足System.out.println(name + "取钱失败,余额不足");}}
5.6lock锁
5.6.1lock锁是什么
Lock锁是JDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大。Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。
5.6.2lock锁的构造器、常用方法
构造器 | 说明 |
public ReentrantLock() | 获得Lock锁的实现类对象 |
方法名称 | 说明 |
void lock() | 获得锁 |
void unlock() | 释放锁 |
5.6.3锁对象建议加上什么修饰
建议使用final修饰,防止被别人篡改
5.6.4释放锁的操作建议放到哪里
建议将释放锁的操作放到finally代码块中,确保锁用完了一定会被释放
private final Lock lk = new ReentrantLock(); // 保护锁对象// 小明和小红都到这里来了取钱public void drawMoney(double money) {// 拿到当前谁来取钱。String name = Thread.currentThread().getName();lk.lock(); // 上锁try {// 判断余额是否足够if (this.money >= money) {// 余额足够,取钱System.out.println(name + "取钱成功,吐出了" + money + "元成功!");// 更新余额this.money -= money;System.out.println(name + "取钱成功,取钱后,余额剩余" + this.money + "元");} else {// 余额不足System.out.println(name + "取钱失败,余额不足");}} finally {lk.unlock();// 解锁}}
6.线程池
6.1认识线程池
线程池就是一个可以复用线程的技术。
6.2不使用线程池的后果
用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的, 创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。
6.3创建线程池
通过ThreadPoolExecutor创建线程池。使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。
【1】参数一:corePoolSize : 指定线程池的核心线程的数量。
【2】参数二:maximumPoolSize:指定线程池的最大线程数量。
【3】参数三:keepAliveTime :指定临时线程的存活时间。
【4】参数四:unit:指定临时线程存活的时间单位(秒、分、时、天)
【5】参数五:workQueue:指定线程池的任务队列。
【6】参数六:threadFactory:指定线程池的线程工厂。
【7】参数七:handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新任务来了该怎么处理)
6.4任务拒绝策略
策略 | 说明 |
ThreadPoolExecutor.AbortPolicy() | 丢弃任务并抛出RejectedExecutionException异常。是默认的策略 |
ThreadPoolExecutor. DiscardPolicy() | 丢弃任务,但是不抛出异常,这是不推荐的做法 |
ThreadPoolExecutor. DiscardOldestPolicy() | 抛弃队列中等待最久的任务 然后把当前任务加入队列中 |
ThreadPoolExecutor. CallerRunsPolicy() | 由主线程负责调用任务的run()方法从而绕过线程池直接执行 |
6.5线程池的注意事项
// 1、定义一个线程任务类实现Runnable接口
public class MyRunnable implements Runnable {// 2、重写run方法,设置线程任务@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "输出:" + i);try {Thread.sleep(Integer.MAX_VALUE);} catch (Exception e) {e.printStackTrace();}}}
}
public static void main(String[] args) {// 目标:创建线程池对象来使用。// 1、使用线程池的实现类ThreadPoolExecutor声明七个参数来创建线程池对象。ExecutorService pool = new ThreadPoolExecutor(3, 5,10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());// 2、使用线程池处理任务!看会不会复用线程?Runnable target = new MyRunnable();pool.execute(target); // 提交第1个任务 创建第1个线程 自动启动线程处理这个任务pool.execute(target); // 提交第2个任务 创建第2个线程 自动启动线程处理这个任务pool.execute(target); // 提交第2个任务 创建第3个线程 自动启动线程处理这个任务pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target); // 到了临时线程的创建时机了pool.execute(target); // 到了临时线程的创建时机了pool.execute(target); // 到了任务拒绝策略了,忙不过来// 3、关闭线程池 :一般不关闭线程池。// pool.shutdown(); // 等所有任务执行完毕后再关闭线程池!
// pool.shutdownNow(); // 立即关闭,不管任务是否执行完毕!}
6.6处理runnable任务
6.4.1ExecutorService的常用方法
方法名称 | 说明 |
void execute(Runnable command) | 执行 Runnable 任务 |
Future<T> submit(Callable<T> task) | 执行 Callable 任务,返回未来任务对象,用于获取线程返回的结果 |
void shutdown() | 等全部任务执行完毕后,再关闭线程池! |
List<Runnable> shutdownNow() | 立刻关闭线程池,停止正在执行的任务,并返回队列中未执行的任务 |
// 2、使用线程池处理任务!看会不会复用线程?Runnable target = new MyRunnable();pool.execute(target); // 提交第1个任务 创建第1个线程 自动启动线程处理这个任务pool.execute(target); // 提交第2个任务 创建第2个线程 自动启动线程处理这个任务pool.execute(target); // 提交第2个任务 创建第3个线程 自动启动线程处理这个任务pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target); // 到了临时线程的创建时机了pool.execute(target); // 到了临时线程的创建时机了pool.execute(target); // 到了任务拒绝策略了,忙不过来// 3、关闭线程池 :一般不关闭线程池。pool.shutdown(); // 等所有任务执行完毕后再关闭线程池!pool.shutdownNow(); // 立即关闭,不管任务是否执行完毕!
6.7处理callable
线程池如何处理Callable任务,并得到任务执行完后返回的结果?
Future<T> submit(Callable<T> command)
6.8通过Executors创建线程池
6.8.1方法
是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象。这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象。
方法名称 | 说明 |
public static ExecutorService newFixedThreadPool(int nThreads) | 创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。 |
public static ExecutorService newSingleThreadExecutor() | 创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。 |
public static ExecutorService newCachedThreadPool() | 线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了60s则会被回收掉。 |
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) | 创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。 |
6.8.2Executors使用可能存在的陷阱
【1】大型并发系统环境中使用Executors如果不注意可能会出现系统风险。
【2】不适合做大型互联网场景的线程池方案
【3】建议使用ThreadPoolExecutor来指定线程池参数,这样可以明确线程池的运行规则,规避资源耗尽的风险。
7.并发、并行
7.1进程
【1】正在运行的程序(软件)就是一个独立的进程。
【2】线程是属于进程的,一个进程中可以同时运行很多个线程。
【3】进程中的多个线程其实是并发和并行执行的。
7.2并发的含义
进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能往前执行,CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发。
7.3并行的含义
在同一个时刻上,同时有多个线程在被CPU调度执行。
相关文章:
day12 多线程
目录 1.概念相关 1.1什么是线程 1.2什么是多线程 2.创建线程 2.1方式一:继承Thread类 2.1.1实现步骤 2.1.2优缺点 2.1.3注意事项 2.2方式二:实现Runnable接口 2.2.1实现步骤 2.2.2优缺点 2.2.3匿名内部类写法 2.3方式三:实现cal…...
DeferredResult 是如何实现异步处理请求的
最近遇到了一个问题,我们的一个接口需要去轮询另一个第三方接口,导致这个接口占用了太多工作线程,这些工作线程长时间 running,我们需要解决这个问题。 于是,我们的方案是:用 DeferredResult 实现接口异步。…...
VUE3——001(03)、开发环境配置(node.js/mvn/java/ngix/tomact/vue3)
嫌麻烦的请下载安装包,有点强迫(懒的)可以看看。 解释:安装目录,即软件安装所在目录,如 node.js 我装在 D:\AppFolder\nodejs 系统变量修改 path增加 安装目录 在系统变量 p…...
TCP/IP_TCP协议
目录 一、TCP协议 1.1 确认应答 1.2 超时重传 1.3 连接管理 1.4 TCP状态 1.5 滑动窗口 1.6 流量控制 1.7 拥塞控制 1.8 延迟应答 1.9 捎带应答 1.10 粘包问题 1.11 异常情况 二、TCP/UDP对比 总结 一、TCP协议 TCP 协议和 UDP 协议是处于传输层的协议。 【TCP协…...
鸿蒙应用框架开发【简单时钟】 UI框架
简单时钟 介绍 本示例通过使用ohos.display接口以及Canvas组件来实现一个简单的时钟应用。 效果预览 使用说明 1.界面通过setInterval实现周期性实时刷新时间,使用Canvas绘制时钟,指针旋转角度通过计算得出。 例如:"2 * Math.PI / …...
MySQL是如何实现数据排序的
MySQL是如何实现数据排序的 MySQL实现数据排序主要依赖于其内部的排序和索引机制。当执行包含ORDER BY子句的SQL查询时,MySQL会采用以下一种或多种策略来对数据进行排序 索引排序 如果ORDER BY子句中的列是表的一个索引(或索引的一部分)&a…...
【测试架构师修炼之道】读书笔记
六大质量属性 效率性能 测试类型:六种-XX属性转化为XX测试 产品测试车轮图 一个软件测试者要从哪些方面(测试类型)用哪些方法(测试方法)去测试产品(质量属性)的关系图 全面性与深度 稳定性测试:多并复异 性能测试: 系统能够正确处理新业…...
C++ Functor仿函数
Functor 对象模拟函数 把类对象,像函数名一样使用。 仿函数(functor),就是使一个类的使用看上去像一个函数。其实现就是类中实现 一个 operator(),这个类就有了类似函数的行为,就是一个仿函数类了。 operator() 语法格式 clas…...
【EI会议征稿通知】第五届大数据、人工智能与软件工程国际研讨会(ICBASE 2024)
重要信息 会议官网:www.icbase.org(查看详情) 中文主页:【往届会后3个月检索】第五届大数据、人工智能与软件工程国际研讨会(ICBASE 2024)_艾思科蓝_学术一站式服务平台 会议时间:2024年9月2…...
微信小程序多端框架实现app内自动升级
多端框架生成的app,如果实现app内自动升级? 一、Android 实现app自动升级,华为应用市场 1、获取 应用市场地址 下载地址 2、在微信开放平台进行配置 应用下载地址:应用市场点击分享,里面有一个复制连接功能 应用市…...
C# Log4Net应用
1 需求分析 日志记录是程序开发中必不可少的环节,对于bug调试和后期项目维护都十分重要.其中Log4net是C#环境下广泛使用的日志记录库,功能十分强大.本教程提供的日志记录需求如下 1,日志文件统一保存到项目启动目录下的logs文件夹 2,以天为单位进行日志…...
pytest8.x版本 中文使用文档-------32.示例:使用自定义目录收集器
默认情况下,pytest 使用pytest.Package来收集包含 __init__.py 文件的目录,使用 pytest.Dir来收集其他目录。如果你想要自定义目录的收集方式,你可以编写自己的pytest.Directory 收集器,并使用 pytest_collect_directory钩子来连接…...
c语言第七天笔记
作业题: 设计TVM(地铁自动售票机)机软件。 输入站数,计算费用,计费规则,6站2元,7-10站3元,11站以上为4元。 输入钱数,计算找零(找零时优先找回面额大的钞票)࿰…...
软件测试经理工作日常随记【8】-UI自动化_加密接口的传输
软件测试经理工作日常随记【8】-UI自动化_加密接口的传输 工具类 #utils_api.py class RequestUtils:classmethoddef send_request_splicing(cls, dicts, url): # 对应请求的入参及请求的函数Logger.logger_in().info(-----------------{}接口开始执行-----------------.for…...
基于FPGA的出租车计费系统设计---第一版--郝旭帅电子设计团队
欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的出租车计费系统设计—第一版 功能说明: 收费标准(里程):起步价5元,包括三公里;三公里之后,每公里2元&#x…...
商汤联合建工社共同打造“住建领域法规标准知识大模型”
近日,商汤科技与中国建筑出版传媒有限公司(下称“建工社”)共同发布“住建领域法规标准知识大模型”,共同探索新型知识服务模式。大模型聚焦建筑行业,以商汤“日日新SenseNova 5.5”大模型体系为基础,结合海…...
基于STM32的智能交通监控系统教程
目录 引言环境准备智能交通监控系统基础代码实现:实现智能交通监控系统 车辆检测模块交通流量分析模块通信与网络系统实现用户界面与数据可视化应用场景:交通管理与优化常见问题与解决方案收尾与总结 引言 随着城市化进程的加快,交通拥堵问…...
Git和TortoiseGit的安装与使用
文章目录 前言一、Git安装步骤查看版本信息 二、TortoiseGit安装中文语言包TortoiseGit 配置不同语言 Git基本原理介绍及常用指令 GitLab添加TortoiseGIT生成SSH Key 前言 Git 提供了一种有效的方式来管理项目的版本,协作开发,以及跟踪和应用文件的变化…...
改进YOLOv5:加入非对称卷积块ACNet,加强CNN 的内核骨架,包含VOC对比实验
🔥🔥🔥 提升多尺度、不规则目标检测,创新提升 🔥🔥🔥 🔥🔥🔥 捕捉图像特征和处理复杂图像特征 🔥🔥🔥 👉👉👉: 本专栏包含大量的新设计的创新想法,包含详细的代码和说明,具备有效的创新组合,可以有效应用到改进创新当中 👉👉👉: �…...
论文解读(12)-Transfer Learning
这个也是看论文的时候看到的,但是对这方面不是理解,需要对这方面知识点进行一个补充。 参考: 迁移学习概述(Transfer Learning)-CSDN博客 1. 什么是Transfer Learning? Transfer Learning就是迁移学习&…...
力扣高频SQL 50题(基础版)第三十八题
文章目录 力扣高频SQL 50题(基础版)第三十八题1484.按日期分组销售产品题目说明实现过程准备数据实现方式结果截图总结 力扣高频SQL 50题(基础版)第三十八题 1484.按日期分组销售产品 题目说明 表 Activities: ---…...
大模型下的视频理解video understanding
数据集 Learning Video Context as Interleaved Multimodal Sequences Motivation: 针对Narrative videos, like movie clips, TV series, etc.:因为比较复杂 most top-performing video perception models 都是研究那种原子动作or人or物 understandin…...
【网络安全】CR/LF注入+Race Condition绕过MFA
未经许可,不得转载。 文章目录 漏洞1:CR/LF注入前言正文漏洞2:Race Condition绕过MFA前言正文漏洞1:CR/LF注入 前言 ExaHub(此处为虚拟名称)是一个专为 Exa 编程语言的爱好者和专业人士量身定制的平台。Exa 语言以其出色的速度和性能而闻名,广泛应用于科学计算、机器学…...
深度学习入门——卷积神经网络
本章的主题是卷积神经网络(Convolutional Neural Network,CNN)。CNN被用于图像识别、语音识别等各种场合,在图像识别的比赛中,基于深度学习的方法几乎都以CNN为基础。本章将详细介绍CNN的结构,并用Python实…...
快团团供货大大团长帮卖团长如何线上结算和支付货款?
一、如何支付结算单? 团长在快团团小程序【我的供货商】—【结算单】—【待支付】中,找到需要支付的结算单,点击【去支付】即可。 当有多笔结算单待支付时,团长可筛选供货商和日期找到需要支付的结算单,点击【去批量…...
vite vue3 Webstorm multiple export width the same name “default“
系统格式不一样,导致代码文件格式冲突导致的,解决方法找到对应的文件,将文件类型切换成LF。...
Transformer预测模型及其Python和MATLAB实现
### 一、背景 在自然语言处理(NLP)领域,传统的序列到序列(Seq2Seq)模型大多依赖于循环神经网络(RNN)和长短期记忆(LSTM)网络。这些模型虽然在许多任务中取得了成功&…...
草的渲染理论
Unity引擎提供了基础的terrain工具,可以制作地形,在上面刷树刷草。对于树,Unity是支持带LOD的Prefab,不同距离显示不同细节的模型,效果还不错。对于草,Unity支持两种方式来刷草,一种是Add Grass…...
Redis:十大数据类型
键(key) 常用命令 1. 字符串(String) 1.1 基本命令 set key value 如下:设置kv键值对,存货时长为30秒 get key mset key value [key value ...]mget key [key ...] 同时设置或者获取多个键值对 getrange…...
bugku-web-source
kali中先用dirsearch工具扫描后台目录,然后用wget -r url/.git命令递归下载后,进入txt文件使用git reflog命令然后只用git show查看作者提交flag日志,用git show 一个一个去尝试,很多假的flag git reflog 是一个 Git 命令&#x…...
今天国内重大新闻事件/重庆seo搜索引擎优化优与略
一、数据与文字的表示方法 (1) 数据格式 (1) 定点数的表示方法 假设用一个 n+1 位的字来表示一个定点数 x,xn 放在最左位置,并用数值 0 和 1 分别代表正号和负号,其余位数代表它的量值,小数点…...
wordpress去除无用标签/百度怎么搜索关键词
在使用FTP向服务器传送问文件的时候,要注意选择传输模式,如果服务器用的是linux,那么一定要选二进制模式,否则传送文件的时候会出错转载于:https://blog.51cto.com/wll2015/1655774...
百度自动提交/seo关键词优化技术
附Java/C/C/机器学习/算法与数据结构/前端/安卓/Python/程序员必读书籍书单大全: 书单导航页(点击右侧 极客侠栈 即可打开个人博客):极客侠栈 ①【Java】学习之路吐血整理技术书从入门到进阶最全50本(珍藏版) ②【算法…...
西安做网站程序/搜索引擎排名查询
Django模型Django 对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。 Django 为这些数据库提供了统一的调用API。 我们可以根据自己业务需求选择不同的数据库。 MySQL 是 Web 应用中最常用的数据库。本章节我们将以 Mysql 作为实例…...
做自媒体的网站/深圳seo关键词优化外包公司
$()、用来作命令替换${ }用来作变量替换(以下内容来自shell十三问)(1). 变量的界定$ AB$ echo $AB该命令执行时,将AB整体看作一个变量,而不是变量$A与字母B的连接。$ AB$ echo ${A}B该命令执行后将输出:BB(2). 特…...
做网站要多少像素/做竞价托管的公司
大家都知道使用线程的2种方式,一是继承Thread类,二是实现Runnable接口。实际上,即使你实现了Runnable接口,终于还是要构造一个Thread类的对象。看过Thread源码发现,事实上这个Thread类也实现了Runnable接口,…...