Java多线程(超详细版!!)
Java多线程(超详细版!!)
文章目录
- Java多线程(超详细版!!)
- 1. 线程 进程 多线程
- 2.线程实现
- 2.1线程创建
- 2.1.1 继承Thread类
- 2.1.2 实现runnable接口
- 2.1.2.1 思考:为什么推荐使用runnable接口?
- 2.1.2.1.1 更高的灵活性(避免单继承限制)
- 2.1.2.1.2 任务与线程分离(更好的设计理念)
- 2.1.3 实现callable接口
- 2.1.4 线程并发问题:买票案例
- 2.1.5 龟兔赛跑
- 2.2多线程详解
- 2.2.1 静态代理模式
- 2.3 Lamba表达式
- 2.3.1Lambda表达式的推导:
- 3.线程状态
- 3.1 停止线程
- 3.2 线程休眠
- 3.3 线程礼让
- 3.4 线程强制执行
- 3.5 观察测试线程的状态
- 3.6 线程的优先级
- 3.6.1线程优先级的设置和获取
- 3.7 守护线程
- 4.线程同步
- 4.1 三大不安全案例
- 4.1.1 不安全的买票:
- 4.1.2 线程不安全的例子:
- 4.2 同步方法
- 4.2.1 synchronized方法
- 4.2.2 synchronized块
1. 线程 进程 多线程
线程(thread):是cpu调度和执行的单位。
进程(precess):是执行程序的一次执行过程。一个进程可以有多个线程,如视频中同时听声音,看图像,看弹幕。
- 说起进程,就不得不说下程序。程序是指令和数据的有序集合,其本身没有任何运
行的含必,是一个静恋的概念。 - 而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单元
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的的单位。
注意:很多多线程是模拟出来的,真正的多线程是指有多个Cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个Cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错局。
普通方法调用和多线程的区别如图:
2.线程实现
2.1线程创建
2.1.1 继承Thread类
在这类方法中,我们利用createThread01继承Thread类,通过.start()方法实现线程启动。继承 Thread 后,必须重写 run() 方法,因为 run() 方法定义了线程执行的具体任务。
public class createThread01 extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("hello "+i);}}public static void main(String[] args) {createThread01 t1 = new createThread01();t1.start();for (int i = 0; i < 100; i++) {System.out.println("你好 "+i);// 穿插进行}}
}
程序启动后,主线程运行 main 方法。调用 t1.start() 后,JVM 创建一个新线程,新线程执行 run() 方法,打印 “hello”。
通过观察,我们会发现,结果并不是我们想象中的按照顺序输出,而是穿插的输出。任由计算机CPU的调度执行。
2.1.2 实现runnable接口
在这段代码中,我们使用createThread02 实现了 Runnable 接口。Runnable 是一个函数式接口,定义了一个抽象方法 run()。实现 Runnable 接口的类需要提供 run() 方法的具体实现。
public class createThread02 implements Runnable{@Overridepublic void run() {System.out.println("hello");}public static void main(String[] args) {createThread02 t1 = new createThread02();new Thread(t1).start();}
}
此代码通过主线程运行 main 方法,创建 createThread02 实例 t1。创建一个新的 Thread 对象,并将 t1 作为参数传递。调用 start() 后,JVM 创建一个新线程,新线程执行 t1 的 run() 方法,打印 “hello”。主线程和新建的线程并发运行。
2.1.2.1 思考:为什么推荐使用runnable接口?
2.1.2.1.1 更高的灵活性(避免单继承限制)
由于Java 是单继承语言,一个类只能继承一个父类。如果继承了 Thread 类,这个类就无法再继承其他类,限制了类的扩展能力。故实现 Runnable 接口不影响类的继承结构。一个类可以实现多个接口(包括 Runnable),同时还能继承其他类。这使得 Runnable 方式更适合需要继承其他类的复杂场景。
例如:
class MyClass extends SomeBaseClass implements Runnable {@Overridepublic void run() {System.out.println("Running in a thread");}
}
这里 MyClass 可以继承 SomeBaseClass 的功能,同时通过实现 Runnable 具备线程任务的能力。
2.1.2.1.2 任务与线程分离(更好的设计理念)
继承 Thread 类将线程(执行机制)和任务(run() 方法的逻辑)绑定在一起,代码结构不够清晰。实现 Runnable 接口将任务逻辑与线程执行分离,Runnable 对象仅定义任务,线程由 Thread 类负责。这种分离符合面向对象设计中的 单一职责原则,提高了代码的可读性和可维护性。
示例:
Runnable task = () -> System.out.println("Task running");
new Thread(task).start(); // 线程 1 执行任务
new Thread(task).start(); // 线程 2 复用同一个任务
一个 Runnable 对象可以被多个线程复用,逻辑更清晰。
2.1.3 实现callable接口
Callable 是 Java 5 引入的并发接口,位于 java.util.concurrent 包中。与 Runnable 不同,Callable 的 call() 方法,其特点是:
-
有返回值:可以返回任务执行的结果(泛型类型)。
-
可抛出异常:允许抛出受检异常(Exception 及其子类)。
2.1.4 线程并发问题:买票案例
我们设置了三个人员来买票,即创建了三个进程。
public class buy implements Runnable{private int ticket = 10;@Overridepublic void run() {//买票逻辑while(true) {if(ticket > 0) {System.out.println(Thread.currentThread().getName()+"买到了票"+ticket--);//先取值后减try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}else {break;}}}public static void main(String[] args) {buy buy = new buy();new Thread(buy,"me").start();new Thread(buy,"you").start();new Thread(buy,"bad man").start();}
}
测试结果:
但是结果通过发现,一个票会被两个人同时买走。多个数据操作同一个资源,数据紊乱。这种问题,后期我们通过线程同步解决。
2.1.5 龟兔赛跑
public class rabbitAndTurtle implements Runnable{private String winner;@Overridepublic void run() {for (int i = 0; i <= 1000; i++) {if(Thread.currentThread().getName().equals("Rabbit")&&i%10==0) {//让兔子休眠try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}boolean flag = gameover(i);if(flag) {break;}System.out.println(Thread.currentThread().getName()+" steps is"+i);}}public boolean gameover(int step) {if (winner != null) {//已经产生了冠军return true;} else {//还未找到冠军if (step == 1000) {winner = Thread.currentThread().getName();System.out.println("the winner is "+winner);return true;}return false;}}public static void main(String[] args) {rabbitAndTurtle r = new rabbitAndTurtle();new Thread(r,"rabbit").start();new Thread(r,"turtle").start();}
}
我们通过手动将兔子进程休眠,让每次乌龟进程跑赢。
2.2多线程详解
线程的底层实现就是静态代理模式。
2.2.1 静态代理模式
前提条件
1.真实对象和代理对象都要实现同一个接口
代理对象要代理真实角色
以婚庆公司为例子
public class staticProxy implements marry{//静态代理模式//人生四大喜事:// 久旱逢甘露// 他乡遇故知// 洞房花烛夜// 金榜题名时@Overridepublic void Happywedding() {}public static void main(String[] args) {weddingCompany weddingCompany = new weddingCompany(new you());weddingCompany.Happywedding();}}interface marry{void Happywedding();
}class you implements marry{//个人@Overridepublic void Happywedding() {System.out.println("我要结婚啦,猴嗨森");}
}
class weddingCompany implements marry{//婚庆公司private marry target;//目标结婚对象@Overridepublic void Happywedding() {before();target.Happywedding();//调用对象的特定方法(已被重写)after();}weddingCompany(marry target) {//把目标对象传进去this.target = target;}public void before() {System.out.println("筹备婚礼");}public void after() {System.out.println("收尾款");}
}
婚庆公司实现了you的方法,无须you创造对象实现方法。代理对象可以做很多真实对象做不了的事情,真实对象做自己的事情。
“代理对象可以做很多真实对象做不了的事情”:
- 代理对象(Proxy)是一个中间层,负责在调用真实对象(Real Subject)之前或之后执行额外的逻辑。这些逻辑可能是真实对象不具备或不适合直接实现的,例如日志记录、权限检查、事务管理、延迟加载、线程管理等。
- 代理对象通过扩展功能,增强了真实对象的行为,而不改变真实对象的核心逻辑。
“真实对象做自己的事情”:
真实对象(Real Subject)专注于实现其核心业务逻辑,不需要关心与业务无关的附加功能(如日志、同步、缓存等)。
代理模式通过将非核心逻辑分离到代理对象中,保持真实对象的简单性和单一职责。
我们由婚庆公司这个例子可以得出。我们每次创建出来的线程,之所以要实现Runable接口,目的就是为了和Thread类实现统一的接口,使Thread能够代理我们新创建的类,从而调用我们重写的Run方法。避免我们自己调用。
2.3 Lamba表达式
Lambda表达式(闭包):java8的新特性,lambda运行将函数作为一个方法的参数,也就是函数作为参数传递到方法中。使用lambda表达式可以让代码更加简洁。
Lambda表达式的使用场景:用以简化接口实现。
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
例如:
public interface Runnable{public abstract void run();
2.3.1Lambda表达式的推导:
最初我们如果想要写一个类实现一个接口,我们就需要这样写。
public class lambdaTest {public static void main(String[] args) {like ilike = new ilike();ilike.like(520);}
}class ilike implements like{@Overridepublic void like(int i) {System.out.println("i like you "+i);}
}interface like {void like(int i);
}
通过分析简化,我们可以变换成这样,将一个外部类,加上static关键字。实现一个静态内部类。
public class lambdaTest {static class ilike implements like{//转变为静态内部类@Overridepublic void like(int i) {System.out.println("i like you "+i);}}public static void main(String[] args) {like ilike = new ilike();ilike.like(520);}
}interface like {void like(int i);
}
进一步简化,我们可以转变为局部内部类。
public class lambdaTest {public static void main(String[] args) {class ilike implements like{//实现局部内部类@Overridepublic void like(int i) {System.out.println("i like you "+i);}}like ilike = new ilike();ilike.like(520);}
}interface like {void like(int i);
}
再进一步简化,我们可以转变为匿名内部类。
public class lambdaTest {public static void main(String[] args) {// 创建匿名内部类实例并赋值给变量Like like = new Like() {@Overridepublic void lambda(int i) {System.out.println("i like " + i);}};// 通过实例调用 lambda 方法,传入参数like.lambda(5);}
}// 接口定义
interface Like {void lambda(int i);
}
在jdk1.8出现后,工程师创造了一种更加完善,简化的书写规范——lambda表达式。
public class lambdaTest {public static void main(String[] args) {// 利用lambda表达式实现方法Like like = (i)->{System.out.println("i like "+i);} ;like.lambda(5);}
}// 接口定义
interface Like {void lambda(int i);
}
由于在接口的方法中,已经定义了每⼀个参数的类型是什么。而且在使用lambda表达式实现接口的时候,必须要保证参数的数量和类 型需要和接口中的方法保持⼀致。因此,此时lambda表达式中的参数的类型可以省略不写。以上就是Lambda表达式相关内容。
3.线程状态
线程的状态分为一下几种:
其具体的运行转化过程如下:
接下来,笔者将为你详细讲述线程每个状态的操作。
3.1 停止线程
不推荐使用JDK提供的 stop()、destroy0方法。【已废弃】
推荐线程自己停止下来。
建议使用一个标志位进行终止变量当flag=false,则终止线程运行。
测试案例:
public class ThreadStop implements Runnable {private boolean flag = true;@Overridepublic void run() {int i = 0;while(flag) {System.out.println("running "+ i++);}}public void shutdown() {this.flag = false;}public static void main(String[] args) {ThreadStop threadStop = new ThreadStop();new Thread(threadStop).start();for (int i = 0; i < 1000; i++) {if (i == 900) {threadStop.shutdown();System.out.println("stop!");}System.out.println(i);}}}
在这里,我们使用了一个外部方法shutdown将线程停止了下来。
3.2 线程休眠
关键词:sleep
在java中参数1000,即为1000ms = 1s 。
我们通过一个例子,实现打印当前系统时间的例子。代码中,我们调用了** **方法获取当前时间,通过休眠1s实现每秒打印。打印完后,将新的时间赋值,完成时间更新操作。
import java.text.SimpleDateFormat;
import java.util.Date;public class threadSleeptest {//打印当前系统时间public static void main(String[] args) {Date date = new Date(System.currentTimeMillis());while(true) {try {Thread.sleep(1000);System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));//SimpleDateFormat 是一个用于格式化和解析日期的类,属于 java.text 包date = new Date(System.currentTimeMillis());} catch (InterruptedException e) {e.printStackTrace();}}}
}
测试结果:
根据结果分析,我们可以得出系统按照每分每秒每时实现当前时间打印。
3.3 线程礼让
关键词:yield
-
礼让线程,让当前正在执行的线程暂停,但不阻塞
-
将线程从运行状态转为就绪状态
-
让cpu重新调度,礼让不一定成功!看CPU心情
我们创建了两个线程,验证是否能实现线程礼让功能。
public class threadYield implements Runnable {@Overridepublic void run() {System.out.println("hello "+Thread.currentThread().getName());Thread.yield();//线程礼让System.out.println("bye "+Thread.currentThread().getName());}public static void main(String[] args) {threadYield thread = new threadYield();new Thread(thread,"a").start();new Thread(thread,"b").start();}}
输出结果:
hello a
hello b
bye b
bye a
我们可以得出,cpu礼让了线程a,输出了hello b语句。
3.4 线程强制执行
关键词:Join
Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞。可以想像成插队
样例:
public class forceTest extends Thread {@Overridepublic void run() {System.out.println(100+" vip");}public static void main(String[] args) {forceTest test = new forceTest();test.start();for (int i = 0; i < 10; i++) {if(i==5) {try {test.join();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(i);}}
}
输出结果:
0
1
2
3
4
100 vip
5
6
7
8
9
通过join方法,强制执行run方法。
3.5 观察测试线程的状态
线程状态。线程可以处于以下状态之一:
- NEW 尚未启动的线程处于此状态。
- RUNNABLE 在Java虚拟机中执行的线程处于此状态。
- BLOCKED 被阻塞等待监视器锁定的线程处于此状态。
- WAITING 正在等待另一个线程执行特定动作的线程处于此状态。
- TIED WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
- TERMINATED已退出的线程处于此状态。
一个线程可以在给定时间点处于一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态。
3.6 线程的优先级
在Java中,线程优先级是指调度器根据线程的优先级决定哪个线程应该优先获得CPU的时间片。在多线程编程中,线程优先级是一个影响线程调度的重要因素。Java提供了线程优先级机制,允许开发者为不同的线程设置优先级,以便操作系统调度器在分配CPU时间时能够优先处理高优先级的线程。
在Java中,每个线程都有一个优先级,它是一个整数值,范围从1到10。Java定义了三个常量用于表示线程优先级的标准值:
-
Thread.MIN_PRIORITY: 1,表示最低优先级。
-
Thread.NORM_PRIORITY: 5,表示默认的普通优先级。
-
Thread.MAX_PRIORITY: 10,表示最高优先级。
-
默认情况下,Java中的线程继承创建它的父线程的优先级。例如,主线程的优先级为5,因此任何由主线程创建的新线程默认也具有优先级5。
3.6.1线程优先级的设置和获取
Java提供了两种方法来设置和获取线程的优先级:
- setPriority(int priority): 用于设置线程的优先级。
- getPriority(): 用于获取线程的优先级。
public class ThreadPriorityExample {public static void main(String[] args) {Thread thread1 = new Thread(() -> {System.out.println("Thread 1 is running with priority: " + Thread.currentThread().getPriority());});Thread thread2 = new Thread(() -> {System.out.println("Thread 2 is running with priority: " + Thread.currentThread().getPriority());});thread1.setPriority(Thread.MIN_PRIORITY);thread2.setPriority(Thread.MAX_PRIORITY);thread1.start();thread2.start();}
}
在这个例子中,我们创建了两个线程,并分别为它们设置了最低优先级和最高优先级。运行结果可能会因操作系统的调度策略而异,但通常情况下,高优先级的线程更有可能先执行。
3.7 守护线程
关键词:setdaemon
在Java中,守护线程(Daemon Thread)是一种特殊的线程,在后台运行并提供服务支持。当JVM中仅剩下守护线程时,JVM会自动退出,因为此时没有用户线程需要继续执行1。
默认情况下,主线程和其他通过Thread
类创建的线程都是非守护线程。要将一个线程设置为守护线程,可以在调用start()之前使用
setDaemon(true)`方法来实现。需要注意的是,一旦线程启动后就不能更改其守护状态2。
线程分为用户线程和守护线程
虛拟机心须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如:后台记录操作日志,监控内存,垃圾回收等待.
以下是设置守护线程的一个简单例子:
public class DaemonThreadExample {public static void main(String[] args) throws InterruptedException {Thread daemonThread = new Thread(() -> {while (true) {System.out.println("Daemon thread is running...");try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("Daemon thread interrupted.");}}});// 将线程设为守护线程daemonThread.setDaemon(true);// 启动守护线程daemonThread.start();// 主线程休眠一段时间后结束Thread.sleep(3000);System.out.println("Main thread finished.");}
}
在这个例子中,守护线程会在后台持续打印消息直到主线程完成。由于只有守护线程存活,JVM随后终止整个程序。
4.线程同步
线程同步发生的情况:多个线程访问同一个对象时,并且某些线程还想修改这个对象的时候,这个时候就用到了线程同步。多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。
形成条件:锁+队列
关键词:synchronized
4.1 三大不安全案例
现在笔者将提供三个例子,为读者讲解这些典型例子中,哪里有问题,为后期使用线程同步来解决埋下伏笔。
4.1.1 不安全的买票:
在当前例子中:
public class buy implements Runnable{private int ticket = 10;@Overridepublic void run() {//买票逻辑while(true) {if(ticket > 0) {System.out.println(Thread.currentThread().getName()+"买到了票"+ticket--);//先取值后减try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}else {break;}}}public static void main(String[] args) {buy buy = new buy();new Thread(buy,"me").start();new Thread(buy,"you").start();new Thread(buy,"bad man").start();}
}
输出结果:
you买到了票9
bad man买到了票8
me买到了票10
bad man买到了票7
me买到了票7
you买到了票6
bad man买到了票5
me买到了票4
you买到了票4
you买到了票3
me买到了票2
bad man买到了票3
bad man买到了票1
me买到了票0
you买到了票1
三个对象买票,但会出现多个人买到一张票,线程不安全。多个人会操作同一个资源。
4.1.2 线程不安全的例子:
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;public class unsafeExample{public static void main(String[] args) {List s = new LinkedList();unsafeExample un = new unsafeExample();for (int i = 0; i < 10000; i++) {new Thread(()->{s.add(Thread.currentThread().getName());}).start();}System.out.println(s.size());}
}
9999
通过观察结果,我们会发现,会有线程泄漏出去,无法保证线程安全。
4.2 同步方法
通过4.1的三个例子,我们发现了使用线程存在安全问题。这一环节我们就可以时候同步的方法保证一个对象(线程)操作一个资源。维护线程操作的安全性。
由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是 synchronized 关键宇,它包括两种用法:
synchronized
方法 和synchronized
块.
4.2.1 synchronized方法
同步方法:public synchronized void method(int args) g•synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁。
缺陷:若将一个大的方法申明为synchronized 将会影响效率
因此对于上面的买票例子,我们通过锁掉buy()
方法,实现一个对象操作一个资源。保证了线程的安全性。
public class buy implements Runnable{private int ticket = 100;private boolean flag = true;@Overridepublic void run() {//买票逻辑while (flag) {try {buy();} catch (InterruptedException e) {e.printStackTrace();}}}public synchronized void buy() throws InterruptedException {//判断票是否买完if(ticket > 0) {System.out.println(Thread.currentThread().getName()+"买到了票"+ticket--);//先取值后减Thread.sleep(100);}else {flag = false;return;}}public static void main(String[] args) {buy buy = new buy();new Thread(buy,"you").start();new Thread(buy,"me").start();new Thread(buy,"bad man").start();}
}
通过使用同步方法,结果如我们想的一样。
4.2.2 synchronized块
使用方法:synchronized(){}
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;public class unsafeExample{public static void main(String[] args){List s = new LinkedList();unsafeExample un = new unsafeExample();for (int i = 0; i < 222000; i++) {new Thread(()->{synchronized (s) {s.add(Thread.currentThread().getName());//拟合排队的逻辑}}).start();}System.out.println(s.size());}
}
以上便是笔者对于Java线程的有限见解,笔者编文不易,欢迎评论区大佬指点补错!希望这个讲解能帮助你深入理解代码的实现过程!如果有疑问,欢迎评论区交流!
相关文章:
Java多线程(超详细版!!)
Java多线程(超详细版!!) 文章目录 Java多线程(超详细版!!)1. 线程 进程 多线程2.线程实现2.1线程创建2.1.1 继承Thread类2.1.2 实现runnable接口2.1.2.1 思考:为什么推荐使用runnable接口?2.1.2.1.1 更高的…...
超详细fish-speech本地部署教程
本人配置: windows x64系统 cuda12.6 rtx4070 一、下载fish-speech模型 注意:提前配置好git,教程可在自行搜索 git clone https://gitclone.com/github.com/fishaudio/fish-speech.git cd fish-speech 或者直接进GitHub中下载也可以 …...
Flink和Spark的选型
在Flink和Spark的选型中,需要综合考虑多个技术维度和业务需求,以下是在项目中会重点评估的因素及实际案例说明: 一、核心选型因素 处理模式与延迟要求 Flink:基于事件驱动的流处理优先架构,支持毫秒级低延迟、高吞吐的…...
解锁 DevOps 新境界 :使用 Flux 进行 GitOps 现场演示 – 自动化您的 Kubernetes 部署
前言 GitOps 是实现持续部署的云原生方式。它的名字来源于标准且占主导地位的版本控制系统 Git。GitOps 的 Git 在某种程度上类似于 Kubernetes 的 etcd,但更进一步,因为 etcd 本身不保存版本历史记录。毋庸置疑,任何源代码管理服务…...
【从零实现JsonRpc框架#1】Json库介绍
1.JsonCpp第三方库 JSONCPP 是一个开源的 C 库,用于解析和生成 JSON(JavaScript Object Notation)数据。它提供了简单易用的接口,支持 JSON 的序列化和反序列化操作,适用于处理配置文件、网络通信数据等场景。 2.Jso…...
使用FastAPI和React以及MongoDB构建全栈Web应用02 前言
Who this book is for 本书适合哪些人阅读 This book is designed for web developers who aspire to build robust, scalable, and efficient web applications. It caters to a broad spectrum of developers, from those with foundational knowledge to experienced prof…...
JavaScript中的数据类型
目录 前言 基本类型 Number 特殊的数值NaN Infinity和-Infinity String Boolean Undefined null Symbol Undefined和Null的区别 引用类型 Object(对象) Array(数组) Function(函数) 函数声…...
AI 助力,轻松进行双语学术论文翻译!
在科技日新月异的今天,学术交流中的语言障碍仍然是科研工作者面临的一大挑战。尤其是对于需要查阅大量外文文献的学生、科研人员和学者来说,如何高效地理解和翻译复杂的学术论文成为了一大难题。然而,由Byaidu团队推出的开源项目PDFMathTrans…...
第3.2.3节 Android动态调用链路的获取
3.2.3 Android App动态调用链路 在Android应用中,动态调用链路指的是应用在运行时的调用路径。这通常涉及到方法调用的顺序和调用关系,特别是在应用的复杂逻辑中,理解这些调用链路对于调试和性能优化非常重要。 1,动态调用链路获…...
【Android】文件分块上传尝试
【Android】文件分块上传 在完成一个项目时,遇到了需要上传长视频的场景,尽管可以手动限制视频清晰度和视频的码率帧率,但仍然避免不了视频大小过大的问题,且由于服务器原因,网络不太稳定。这个时候想到了可以将文件分…...
大模型中的三角位置编码实现
Transformer中嵌入表示 位置编码的实现 import torch import math from torch import nn# 词嵌入位置编码实现 class EmbeddingWithPosition(nn.Module):"""vocab_size:词表大小emb_size: 词向量维度seq_max_len: 句子最大长度 (人为设定,例如GPT2…...
深入详解人工智能数学基础——微积分中的自动微分及其在PyTorch中的实现原理
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQL server,Oracle,mysql,postgresql等进行开发应用…...
【Linux学习笔记】系统文件IO之重定向原理分析
【Linux学习笔记】系统文件IO之重定向原理分析 🔥个人主页:大白的编程日记 🔥专栏:Linux学习笔记 文章目录 【Linux学习笔记】系统文件IO之重定向原理分析前言一. 系统文件I/01.1 一种传递标志位的方法1.2 hello.c写文件:1.3 he…...
《React Native与Flutter:社交应用中用户行为分析与埋点统计的深度剖析》
React Native与Flutter作为两款备受瞩目的跨平台开发框架,正深刻地影响着应用的构建方式。当聚焦于用户行为分析与埋点统计时,它们各自展现出独特的策略与工具选择,这些差异和共性不仅关乎开发效率,更与社交应用能否精准把握用户需…...
Cesium高度参考系统
🌍 Cesium高度参考系统趣味探索 🚀 高度参考系统形象比喻 想象一下,你正在玩一个积木游戏: CLAMP_TO_GROUND:积木被"强力胶水"粘在桌面上,无论桌面高低起伏如何 RELATIVE_TO_GROUND:积木放在"微型支架"上,始终保持离桌面固定距离 NONE:积木漂…...
海纳思(Hi3798MV300)机顶盒遇到海思摄像头
海纳思机顶盒遇到海思摄像头,正好家里有个海思Hi3516的摄像头模组开发板,结合机顶盒来做个录像。 准备工作 海纳斯机顶盒摄像机模组两根网线、两个电源、路由器一块64G固态硬盘 摄像机模组和机顶盒都接入路由器的LAN口,确保网络正常通信。 …...
[python] 类
一 介绍 具有相同属性和行为的事物的通称,是一个抽象的概念 三要素: 类名,属性,方法 格式: class 类名: 代码块 class Pepole:name "stitchcool"def getname(self):return self.name 1.1 创建对象(实例化) 格式: 对象名 类名() p1 Pepole()…...
Python中的事件循环是什么?事件是怎么个事件?循环是怎么个循环
在Python异步编程中,事件循环(Event Loop)是核心机制,它通过单线程实现高效的任务调度和I/O并发处理。本文将从事件的定义、循环的运行逻辑以及具体实现原理三个维度展开分析。 一、事件循环的本质:协程与任务的调度器…...
单片机-STM32部分:11、ADC
飞书文档https://x509p6c8to.feishu.cn/wiki/OclUwlkifiRKR2k6iLbczn5tn8g STM32的ADC是一种逐次逼近型模拟数字转换器。 是用于将模拟形式的连续信号转换为数字形式的离散信号的一类设备。 逐次逼近型ADC的原理图下: STM32f103系列有3个ADC,精度为12…...
【含文档+PPT+源码】基于微信小程序的社区便民防诈宣传系统设计与实现
项目介绍 本课程演示的是一款基于微信小程序的社区便民防诈宣传系统设计与实现,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套…...
Laravel 安全:批量赋值 fillable 与 guarded
Laravel 的模型中有两个 protected 字段 fillable 与 guarded,注意:必须是 protected 以上开放程度。 我们经常通过提交表单进行数据的增删改,为了方便的进行数据批量修改操作 Laravel 提供了批量赋值机制: 假如我们想要在数据库…...
[杂谈随感-13]: 人的睡眠,如何布置床的位置比较有安全?感?
睡眠环境中的床位布置直接影响心理安全感与睡眠质量,需从空间防御性、人体感知机制及环境心理学多维度综合设计。 以下基于科学原理与实践案例,系统解析床位布置的核心策略: 一、空间防御性布局:构建心理安全边界 背靠实体墙&a…...
协议路由与路由协议
协议路由”和“路由协议”听起来相似,但其实是两个完全不同的网络概念。下面我来分别解释: 一、协议路由(Policy-Based Routing,PBR) ✅ 定义: 协议路由是指 根据预设策略(策略路由࿰…...
内网穿透系列三:开源本地服务公网映射工具 tunnelmole
以下是对 tunnelmole 简要介绍: tunnelmole 是一款开源的内网穿透工具,一行命令就能把本地http服务映射成公网可访问的链接提供公共免费的网络服务,直接下载运行命令即可使用,也支持自行配置搭建私有客户端、服务端参考开源地址&…...
发行基础:本地化BUG导致审核失败
1、早上收到邮件,Steam客服说本地化功能找不到,无法切换多国语言,所以正式版V1.0程序未通过。 大脑瞬间有要爆炸的感觉,测试后发现V1以及demo都存在同样问题。 属于重大BUG,需要立即解决,最高优先级。 2、…...
QB/T 1649-2024 聚苯乙烯泡沫塑料包装材料检测
聚苯乙烯泡沫塑料包装材料是指以可发行聚苯乙烯珠粒为原料,经加热预发泡后在模具中加热成型而制得,具有闭孔结构的聚苯乙烯泡沫塑料包装材料。 QB/T 1649-2024聚苯乙烯泡沫塑料包装材料检测项目: 测试项目 测试标准 外观 QB/T 1649 气味…...
【Day 24】HarmonyOS端云一体化开发:云函数
一、端云开发核心架构 1. 技术栈对比 维度传统开发模式HarmonyOS端云一体化方案优势 开发工具需独立配置前后端环境DevEco Studio统一开发端云代码降低60%环境搭建时间部署流程手动部署服务器与数据库一键部署至AGC Serverless免运维,自动弹性伸缩通信安全需自行实…...
大模型(LLMs)强化学习——RLHF及其变种
大模型(LLMs)强化学习——RLHF及其变种面 一、介绍一下 LLM的经典预训练Pipeline?二、预训练(Pre-training)篇 具体介绍一下 预训练(Pre-training)?三、有监督微调(Sup…...
20250510解决NanoPi NEO core开发板在Ubuntu core22.04.3系统下适配移远的4G模块EC200A-CN的问题
1、h3-eflasher-friendlycore-jammy-4.14-armhf-20250402.img.gz 在WIN10下使用7-ZIP解压缩/ubuntu20.04下使用tar 2、Win32DiskImager.exe 写如32GB的TF卡。【以管理员身份运行】 3、TF卡如果已经做过会有3个磁盘分区,可以使用SD Card Formatter/SDCardFormatterv5…...
WinCC V7.2到V8.0与S71200/1500系列连接通讯教程以及避坑点
声明:WinCC与PLC连接详细指导与注意避坑点,部分图片和描述来源于网络,如有冒犯,请联系本人删除。 1.环境介绍 自WinCC V7.2版本起,软件新增加了 "SIMATIC S7-1200, S7-1500 Channel"通道,用于WinCC与 S7-1…...
WPF 性能 UI 虚拟化 软件开发人员的思考
UI 虚拟化是 WPF 采用的一项技术,框架会仅创建用户可见的 UI 元素。例如,如果 ListView 中有 1000 个文本块控件,但您只能查看其中的 10 个,那么 VisualTree 中也只会显示 10 个文本块。向下滚动时,不再可见的元素将被…...
服务器综合实验(实战详解)
该文章的目录部分 实验内容 实验完成步骤 虚拟机准备 配置两个虚拟机的本地仓库 虚拟机A: 虚拟机B: 配置SSH公钥互信 虚拟机A: 编辑 虚拟机B: 提供基于bind的DNS服务 虚拟机A: 项目需求1: …...
【动态导通电阻】软硬开关下GaN器件的动态RDSON
2019年,浙江大学的Rui Li、Xinke Wu等人基于双脉冲和多脉冲测试方法,研究了在硬开关和软开关条件下商用氮化镓(GaN)功率器件的动态导通电阻(R DSON )特性。实验结果表明,不同GaN器件在硬开关和软开关条件下的动态R DSON 表现出不同的行为,这些行为受关断电压和频率的影…...
Java基础 5.10
1.方法重写课堂练习 package com.logic.override_; //编写一个Person类 包括属性/private(name, age) 构造器 方法say(返回自我介绍的字符串) //编写一个Student类 继承Person类 增加id score 属性/private 以及构造器 //定义say方法(返回自我介绍的信息) //在main中 分别创建…...
通信原理绪论
(I)信息量:第j条消息中包含的信息定义为:I(j) 消息是信息的表现形式 消息是信息的一种抽象和本质内容 消息中所含的信息量是该消息出现概率的函数,即 I I[P(x)] P(x)越小,I越…...
Maven 插件配置分层架构深度解析
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
jMeter压测环境部署JDK+Groovy+JMeter+Proto+IntelliJ IDEA
为确保 Groovy、JDK 和 JMeter 三者的版本兼容性,需遵循以下核心原则和步骤: 一、版本兼容性对照表 组件推荐版本范围关键兼容规则JDKJava 8/11/17 (LTS)- JMeter 5.6 支持 Java 11/17GroovyGroovy 3.0.7 或 4.0- Groovy 3.x 支持 Java 8-17 - Groovy 4…...
c#建筑行业财务流水账系统软件可上传记账凭证财务管理系统签核功能
# financial_建筑行业 建筑行业财务流水账系统软件可上传记账凭证财务管理系统签核功能 # 开发背景 软件是给岳阳客户定制开发一款建筑行业流水账财务软件。提供工程签证单、施工日志、人员出勤表等信息记录。 # 财务管理系统功能描述 1.可以自行设置记账科目,做凭…...
深度解析 MySQL 与 Spring Boot 长耗时进程:从故障现象到根治方案(含 Tomcat 重启必要性分析)
一、典型故障现象与用户痛点 在高并发业务场景中,企业级 Spring Boot 应用常遇到以下连锁故障: 用户侧:网页访问超时、提交表单无响应,报错 “服务不可用”。运维侧:监控平台报警 “数据库连接池耗尽”,To…...
一种运动平台扫描雷达超分辨成像视场选择方法——论文阅读
一种运动平台扫描雷达超分辨成像视场选择方法 1. 专利的研究目标与意义1.1 研究目标1.2 实际意义2. 专利的创新方法与技术细节2.1 核心思路与流程2.1.1 方法流程图2.2 关键公式与模型2.2.1 回波卷积模型2.2.2 最大后验概率(MAP)估计2.2.3 统计约束模型2.2.4 迭代优化公式2.3 …...
【程序员AI入门:开发】11.从零构建智能问答引擎:LangChain + RAG 实战手册
1、技术选型 组件推荐方案说明文本嵌入模型sentence-transformers/all-MiniLM-L6-v2轻量级且效果较好的开源模型向量数据库FAISS高效的本地向量检索库大语言模型GPT-3.5/开源LLM(如ChatGLM3)根据资源选择云端或本地模型文档处理框架LangChain简化RAG流程…...
《深入理解Linux网络》笔记
《深入理解Linux网络》笔记 前言参考 前言 前段时间看了《深入理解Linux网络》这本书,虽然有些地方有以代码充篇幅的嫌疑,但总体来说还是值得一看的。在这里简单记录一下笔记,记录下对网络新的理解。 内核是如果接受网络包的? 如…...
【计算机视觉】优化MVSNet可微分代价体以提高深度估计精度的关键技术
优化MVSNet可微分代价体以提高深度估计精度的关键技术 1. 代价体基础理论与分析1.1 标准代价体构建1.2 关键问题诊断 2. 特征表示优化2.1 多尺度特征融合2.2 注意力增强匹配 3. 代价体构建优化3.1 自适应深度假设采样3.2 可微分聚合操作改进 4. 正则化与优化策略4.1 多尺度代价…...
致远A8V5-9.0安装包(包含信创版)【附百度网盘链接】
A8适用于中大型企业,基于"以人为中心"的产品理念,致力于为企业构建和完善“数字智能”的协同运营体系,以组织模型为基础,连接各项工作和业务,聚合信息、资源和能力,实现组织内和跨组织的高效协同…...
terminal 共享工具ttyd
ttyd 是一个非常轻量的工具,它可以将你的终端(如 bash)通过 Web 页面共享出去,适合教学、演示、远程协作等场景,而且 支持 macOS、ARM64、Linux 等平台。 ⸻ ✅ 一、ttyd 简介 • 将 shell 包装成 WebSocket 服务&am…...
右值引用的剖析
引入:为什么要有右值引用? 右值引用的存在,就是为了解决左值引用解决不了的问题! 左值引用的问题: 我们知道,左值引用在做参数和做返回值都可以提高效率;但是有时候,我们无法用左…...
MIT XV6 - 1.4 Lab: Xv6 and Unix utilities - find
接上文 MIT XV6 - 1.3 Lab: Xv6 and Unix utilities - primes find 继续实验,实验介绍和要求如下 (原文链接 译文链接) : Write a simple version of the UNIX find program for xv6: find all the files in a directory tree with a specific name. Your solution…...
PyTorch API 8 - 工具集、onnx、option、复数、DDP、量化、分布式 RPC、NeMo
文章目录 torch.nn.inittorch.nn.attention工具集子模块 torch.onnx概述基于 TorchDynamo 的 ONNX 导出器基于TorchScript的ONNX导出器贡献与开发 torch.optim如何使用优化器构建优化器每个参数的选项执行优化步骤optimizer.step()optimizer.step(closure) 基类算法如何调整学习…...
解决使用宝塔Linux部署前后端分离项目遇到的问题
问题一:访问域名转圈圈,显示404,403 没有解决跨域问题,在后端yml中设置content:/prod(生产环境),在前端.env文件中将http://127.0.0.1:8080/替换为公网IP,并在vite.conf…...
力扣top100 矩阵置零
开辟数组来标记元素为0的行和列,然后将对应的行和列的元素全部置为0; class Solution { public:void setZeroes(vector<vector<int>>& matrix) {int n matrix.size();int m matrix[0].size();vector<int> l(m),r(n);for(int i …...