Java多线程
一、线程的简介:
1.普通方法调用和多线程:
2.程序、进程和线程:
在操作系统中运行的程序就是进程,一个进程可以有多个线程
程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念;
进程则是执行程序的一次执行过程,它是一个动态的概念,是系统资源分配的单位;
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义,线程是CPU调度和执行的单位
很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点cpu只能执行一个代码,因为切换的很快所有就有同时执行的错觉
3.核心概念:
(1).线程就是独立的执行路径
(2).在程序运行时即使没有创建线程,后台也会有多个线程,例如主线程,gc线程
(3).main()称为主线程,为系统的入口,用于执行整个程序
(4).在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的
(5).对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
(6).线程会带来额外的开销,如CPU调度时间,并发控制开销
(7).每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
二、线程的创建
1.继承Thread类
(1).自定义线程类继承Thread类
(2).重写run()方法,编写线程执行体
(3).创建线程对象,调用start()方法启动线程
public class TestThread1 extends Thread{@Overridepublic void run(){for(int i = 0;i<20;i++){System.out.println("------")} }public static void main(String[] args){TestThread1 testThread1 = new TestThread1();testThread1.start();for(int i = 0;i<20;i++){System.out.println("Main Thread")} }}
线程不一定立即执行,具体的执行顺序是由CPU调度执行的
子类继承Thread类具备多线程能力,通过子类对象.start()方法启动线程,不建议使用,因为需要避免OOP的单继承局限性
2.实现Runnable接口
(1).定义MyRunnable类实现Runnable接口
(2).实现run()方法,编写线程执行体
(3).创建线程对象,调用start()方法启动线程
public class TestThread2 implements Runnable{@Overridepublic void run(){for(int i = 0;i<20;i++){System.out.println("------")} }public static void main(String[] args){TestThread2 testThread2 = new TestThread2();Thread thread = new Thread(testThread2);thread.start();for(int i = 0;i<20;i++){System.out.println("Main Thread")} }}
实现接口Runnable具有多线程能力,启动线程时传入目标对象并且通过Thread对象.start()方法,推荐使用,可以避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用
(4).初识并发问题:
public class TestThread implements Runnable{private int ticketNums = 10;public void run(){while(true){if(ticketNums<=0){break;}try{Thread.sleep(200);}catch (InterruptedException e){e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"---拿到了第"+ticketNums+"-----票")}}
}
public static void main(String[] args){TestThread ticket = new TestThread();new Thread(ticket,"A").start();new Thread(ticket,"B").start();new Thread(ticket,"C").start();}
(5).龟兔赛跑:
public class Race implements Runnable{private String winner;public void run(){for(int i = 0;i<=100;i++){if(Thread.currentThread().getName().equals("兔子")){try{Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}}boolean flag = gameOver(i);if(flag){break;}System.out.println(Thread.currentThread().getName()+"-->跑了"+j+"步");}}private boolean gameOver(int steps){if(winner!=null){return true;}if(steps==100){winner = Thread.currentThread().getName();System.out.println("Winner:"+winner);return true;}return false;}public static void main(String[] args){Race race = new Race();new Thread(race,"兔子").start();new Thread(race,"乌龟").start(); }}
3.实现Callable接口
(1).实现Callable接口,需要返回值类型
(2).重写call方法,需要抛出异常
(3).创建目标对象
TestCallable t1 = new TestCallable();
(4).创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(1);
(5).提交执行:
Future<Boolean> result1 = ser.submit(t1);
(6).获取结果:
boolean r1 = result1.get();
(7).关闭服务:
ser.shutdownNow();
三、Lambda表达式:
避免匿名内部类定义过多,其实质属于函数式编程的概念,去掉了一堆没有意义的代码
(params) -> expression [表达式]
(params) -> statement [语句]
(params) ->{statement}
函数式接口:
任何接口如果只包含一个抽象方法,那么它就是一个函数式接口;对于函数式接口,可以通过lambda表达式来创建该接口的对象
interface ILike{void lambda();
}
class Like implements ILike{public void lambda(){System.out.println("abc");}}
public class TestLambda1{static class Like2 implements ILike{public void lambda(){System.out.println("bcd");}}public static void main(String[] args){ILike like = new Like();like.lambda();like = new Like2();like.lambda();class Like3 implements ILike{public void lambda(){System.out.println("abc");}}like = new Like3();like.lambda();like = new ILike(){public void lambda(){System.out.println("asd");}}like.lambda();like = ()->{System.out.println("asdf");}like.lambda();}}
总结:
lambda表达式只能在有一行代码的情况下才能简化为一行,如果有多行,那么就用代码块进行包裹。前提是接口为函数式接口。多个参数也可以去掉参数类型,要去掉就都去掉,且必须加上括号
四、线程状态:
更加具体解释:
线程对象的方法:
方法 | 说明 |
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程 |
boolean isAlive() | 测试线程是否处于活动状态 |
停止线程:
不推荐使用JDK提供的stop()以及destroy()方法,建议使用一个标志位充当终止变量,当flag=false时则终止线程运行
public class TestStop implements Runnable{private boolean flag = true;public void run(){int i = 0;while(flag){System.out.println("Run....Thread"+i++);}}public void stop(){this.flag = false;}public static void main(String[] args){TestStop testStop = new TestStop();new Thread(testStop).start();for(int i = 0;i<1000;i++){if(i==900){testStop.stop();System.out.println("Thread Stop!");}}}
}
线程休眠:
sleep(时间)指定当前线程阻塞的毫秒数
sleep()存在异常InterruptedException
sleep时间达到后进行就进入就绪状态
sleep可以模拟网络延时,倒计时等
每一个对象都有一个锁,sleep不会释放锁
public class TestThread implements Runnable{private int ticketNums = 10;public void run(){while(true){if(ticketNums<=0){break;}try{Thread.sleep(200);}catch (InterruptedException e){e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"---拿到了第"+ticketNums+"-----票")}}
}
public static void main(String[] args){TestThread ticket = new TestThread();new Thread(ticket,"A").start();new Thread(ticket,"B").start();new Thread(ticket,"C").start();}
线程礼让:
礼让线程,让当前正在执行的线程暂停,但不会阻塞
将线程从运行状态转为就绪状态
让CPU重新调度线程的执行,礼让不一定成功
public class TestYield{public static void main(String[] args){MyYield myYield = new MyYield();new Thread(myYield,"a").start();new Thread(myYield,"v").start();}
}
class MyYield implements Runnable{public void run(){System.out.println(Thread.currentThread().getName()+"Start");Thread.yield();System.out.prihntln(Thread.currentThread().getName()+"Stop");}
}
Join:
Join合并线程,待此线程执行完毕后,再执行其他线程,其他线程阻塞
可以想像成插队
public class TestJoin{public static void main(String[] args){MyJoin myJoin = new MyJoin();Thread thread = new Thread(myJoin,"a");thread.join();for(int i = 0;i<500;i++){if(i==200){thread.join();}System.out.println("main"+i);}}
}
class MyJoin implements Runnable{public void run(){for(int i = 0;i<1000;i++){System.out.println("VIP"+i);}}
}
线程状态观测:Thread.State
//线程可以处于以下状态之一:
NEW
//尚未启动的线程处于此状态
RUNNABLE
//在Java虚拟机中执行的线程处于此状态
BLOCKED
//被阻塞等待监视器锁定的线程处于此状态
WAITING
//正在等待另一个线程执行特定动作的线程处于此状态
TIMED_WAITING
//正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
TERMINATED
//已退出的线程处于此状态
//一个线程可以在给定时间点处于一个状态
//这些状态是不反应任何操作系统线程状态的虚拟机状态
监测代码:
public class TestState{public static void main(String[] args){Thread thread = new Thread()->{for(int i = 0;i<5;i++){try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}}Thread.state state = thread.getState();thread.start();state = thread.getState();while(state!=Thread.State.TERMINATED){Thread.sleep(100);state = thread.getState();}}
}
线程优先级:
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。优先级低只是意味着调度的概率低,并不是优先级低就不会被调用了,取决于CPU的调度
线程的优先级用数字表示,取值范围1~10。优先级的设定建议在start()调度前:
Thread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
使用以下方式可以改变或获取优先级:
getPriority()/setPriority(int xxx)
public class TestPriority{public static void main(String[] args){System.out.println(Thread.currentThread().getName()+Thread.currentTread().getPriority());MyPriority mp = new MyPriority();Thread t1 = new Thread(mp);Thread t2 = new Thread(mp);Thread t3 = new Thread(mp);Thread t4 = new Thread(mp);Thread t5 = new Thread(mp);Thread t6 = new Thread(mp);t1.start();t2.setPriority(1);t2.start();t4.setPriority(5);t4.start(); t5.setPriority(10);t5.start();}}
class MyPriority implements Runnable{public void run(){System.out.println(Thread.currentThread().getName()+Thread.currentTread().getPriority());}}
守护线程:
线程分为用户线程和守护线程,虚拟机必须确保用户线程执行完毕,虚拟机不用等待守护线程执行完毕
public class TestDaemon{public static void main(String[] args){God god = new God();You you = new You();Thread thread = new Thread(god);thread.setDaemon(true);thread.start();new Thread(you).start();}
}
class God implements Runnable {public void run(){while(true){System.out.println("God Bless You");}}
}
class You implements Runnable {public void run(){for(int i = 0;i<36500;i++){System.out.println("HAPPY");}System.out.println("----Good Bye!-----");}
}
线程同步:
并发:同一个对象被多个线程同时操作
处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象,这时就需要引入线程同步。线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕,下一个线程再次使用
形成条件是队列和锁
队列和锁:
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待使用后释放锁即可。但是锁机制存在以下问题:
(1).一个线程持有锁会导致其他所有需要此锁的线程挂起;
(2).在多线程竞争下加锁和释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
(3).如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题
public class UnsafeTickets {public static void main(String[] args) {BuyTickets buyTickets = new BuyTickets();new Thread(buyTickets,"abc").start();new Thread(buyTickets,"def").start();new Thread(buyTickets,"ghi").start();}
}
class BuyTickets implements Runnable {private int tickNum = 10;boolean flag = true;public void run(){while(flag){try {buy();} catch (InterruptedException e) {e.printStackTrace();}}}public void buy() throws InterruptedException {if(tickNum<=0){flag = false;return;}Thread.sleep(100);System.out.println(Thread.currentThread().getName()+"Buy"+tickNum--);}}
同步方法:
由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块
同步方法:public synchronized void method(int args){}
synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
缺陷:若将一个大的方法申明为synchronized将会影响效率,需要修改的内容才需要锁,锁的太多会导致资源的浪费
public class UnsafeTickets {public static void main(String[] args) {BuyTickets buyTickets = new BuyTickets();new Thread(buyTickets,"abc").start();new Thread(buyTickets,"def").start();new Thread(buyTickets,"ghi").start();}
}
class BuyTickets implements Runnable {private int tickNum = 10;boolean flag = true;public void run(){while(flag){try {buy();} catch (InterruptedException e) {e.printStackTrace();}}}public synchronized void buy() throws InterruptedException {if(tickNum<=0){flag = false;return;}Thread.sleep(100);System.out.println(Thread.currentThread().getName()+"Buy"+tickNum--);}}
同步块:
synchronized(Obj){}
Obj称之为同步监视器,Obj可以是任何对象,但是推荐使用共享资源作为同步监视器;同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class
同步监视器的执行过程:
第一个线程访问,锁定同步监视器,执行其中代码
第二个线程访问,发现同步监视器被锁定,无法访问
第一个线程访问完毕,解锁同步监视器
第二个线程访问,发现同步监视器没有锁,然后锁定并访问
public class UnsafeTickets {public static void main(String[] args) {BuyTickets buyTickets = new BuyTickets();new Thread(buyTickets,"abc").start();new Thread(buyTickets,"def").start();new Thread(buyTickets,"ghi").start();}
}
class BuyTickets implements Runnable {private int tickNum = 10;boolean flag = true;public void run(){while(flag){try {buy();} catch (InterruptedException e) {e.printStackTrace();}}}public void buy() throws InterruptedException {synchronized (this){if(tickNum<=0){flag = false;return;}Thread.sleep(100);System.out.println(Thread.currentThread().getName()+"Buy"+tickNum--);}}}
CopyOnWriteArrayList:
import java.util.concurrent.CopyOnWriteArrayList;/*** ClassName: TestJUC* Package: PACKAGE_NAME* Description:** @Author:JinTaiDu* @Create:2025/1/7 19:29* @Version:1.0*/
public class TestJUC {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();for (int i = 0; i < 10000; i++) {new Thread(()->{list.add(Thread.currentThread().getName());}).start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}
}
死锁:
多个线程各自占有一些共享资源,并且相互等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形。某一个同步块同时拥有两个以上的对象的锁时就有可能会发生死锁问题
产生死锁的四个必要条件:
(1).互斥条件:一个资源每次只能被一个进程使用
(2).请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
(3).不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺
(4).循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
只要想办法破其中的任意一个或多个条件就可以避免死锁发生
/*** ClassName: DeadLock* Package: PACKAGE_NAME* Description:** @Author:JinTaiDu* @Create:2025/1/7 19:34* @Version:1.0*/
public class DeadLock {public static void main(String[] args) {Makeup g1 = new Makeup(0,"abc");Makeup g2 = new Makeup(1,"def");g1.start();g2.start();}
}
class LipStick{}
class Mirror{}
class Makeup extends Thread{static LipStick lipStick = new LipStick();static Mirror mirror = new Mirror();int choice;String girlName;Makeup(int choice, String girlName){this.choice = choice;this.girlName = girlName;}public void run(){try {makeup();} catch (InterruptedException e) {e.printStackTrace();}}private void makeup() throws InterruptedException {if(choice == 0){synchronized(lipStick){System.out.println(this.girlName + "获得口红的锁");Thread.sleep(1000);synchronized(mirror){System.out.println(this.girlName + "获得镜子的锁");}}}else{synchronized(mirror){System.out.println(this.girlName + "获得镜子的锁");Thread.sleep(2000);synchronized(lipStick){System.out.println(this.girlName + "获得口红的锁");}}}}
}
Lock(锁):
从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当
java.util.concurrent.locks.Lock接囗是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象
ReentrantLock类实现了Lock ,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。
import java.util.concurrent.locks.ReentrantLock;/*** ClassName: TestLock* Package: PACKAGE_NAME* Description:** @Author:JinTaiDu* @Create:2025/1/7 19:53* @Version:1.0*/
public class TestLock {public static void main(String[] args) {TestLock2 testLock = new TestLock2();new Thread(testLock).start();new Thread(testLock).start();new Thread(testLock).start();}
}
class TestLock2 implements Runnable{int ticketNums = 10;private final ReentrantLock lock = new ReentrantLock();public void run(){while(true){try{lock.lock();if(ticketNums > 0){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(ticketNums--);}else{break;}}finally {lock.unlock();}}}
}
lock与synchronized的区别:
Lock是显式锁(手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了作用域自动释放
Lock只有代码块锁,synchronized有代码块锁和方法锁
使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
优先使用顺序:Lock >同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方法体之外)
线程协作:生产者消费者模式
应用场景:生产者和消费者问题
假设仓库中只能存放一件物品,生产者将生产出来的产品放入仓库,消费者从仓库中产品取走消费
如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止。如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止。
这是一个线程同步问题,生产者和消费者共享同一个资源并且生产者和消费者之间相互依赖,互为条件:对于生产者,没有生产产品之前,要通知消费者等待,而生产了产品之后,又需要马上通知消费者消费;对于消费者,在消费之后,要通知生产者已经结束消费,需要生产新的产品以供消费
在生产者消费者问题中,仅有synchronized是不够的,synchronized可阻止并发更新同一个共享资源,实现了同步;但是synchronized不能用来实现不同线程之间的消息传递(通信)
Java提供了几个方法解决线程之间的通信问题:
方法名 | 作用 |
wait() | 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度 |
注意:均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常
解决方法一:管程法
生产者:负责生产数据的模块(可能是方法,对象,线程,进程);
消费者:负责处理数据的模块(可能是方法,对象,线程,进程)
缓冲区:消费者不能直接使用生产者的数据,他们之间有个缓冲区
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
/*** ClassName: TestPC* Package: PACKAGE_NAME* Description:** @Author:JinTaiDu* @Create:2025/1/7 20:22* @Version:1.0*/
public class TestPC {public static void main(String[] args) {SynContainer synContainer = new SynContainer();new Productor(synContainer).start();new Consumer(synContainer).start();}
}
class Productor extends Thread {SynContainer synContainer;public Productor(SynContainer synContainer) {this.synContainer = synContainer;}public void run() {for (int i = 0; i < 100; i++) {System.out.println("生产了第"+i+"只鸡");synContainer.push(new Chicken(i));}}
}
class Consumer extends Thread {SynContainer synContainer;public Consumer(SynContainer synContainer) {this.synContainer = synContainer;}public void run() {for (int i = 0; i < 100; i++) {System.out.println("消费了"+synContainer.pop().id+"只鸡");}}
}
class Chicken{int id;public Chicken(int id){this.id = id;}
}
class SynContainer {Chicken[] chickens = new Chicken[100];int count = 0;public synchronized void push(Chicken chicken){if(count == chickens.length){try{this.wait();}catch (InterruptedException e){e.printStackTrace();}}chickens[count++] = chicken;this.notifyAll();}public synchronized Chicken pop(){if(count == 0){try{this.wait();}catch(InterruptedException e){e.printStackTrace();}}count--;Chicken chicken = chickens[count];this.notifyAll();return chicken;}
}
解决方法二:信号灯法
相关文章:
Java多线程
一、线程的简介: 1.普通方法调用和多线程: 2.程序、进程和线程: 在操作系统中运行的程序就是进程,一个进程可以有多个线程 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念; 进程则是执行程序的一次执…...
C++ 复习总结记录四
C 复习总结记录四 主要内容 1、构造函数其它要点 2、static 成员 3、友元 4、内部类 5、匿名对象 6、拷贝对象时编译器的优化 一 构造函数其它要点 1.1 构造函数体赋值 创建对象时,编译器调用构造函数,给对象中各个成员变量一个合适初始值 cl…...
Oracle Dataguard 需要配置的参数详解
Oracle Dataguard 需要配置的参数详解 目录 Oracle Dataguard 需要配置的参数详解一、数据库名:DB_NAME二、数据库唯一名:DB_UNIQUE_NAME三、LOG_ARCHIVE_CONFIG四、LOG_ARCHIVE_DEST_1五、LOG_ARCHIVE_DEST_2六、LOG_ARCHIVE_DEST_3七、LOG_ARCHIVE_DES…...
Java 内部类与异常类
目录 1.Java 内部类 2.Java 匿名类 1. 匿名类继承一个父类 2. 匿名类实现一个接口 3.Java 异常类 4.Java 异常的分类 1. Throwable类 2. Error类 3. Exception类 5.Java 常见的异常 1. NullPointerException(空指针异常) 2. ClassCastException(类转换异常) 3. In…...
Matlab仿真径向受压圆盘光弹图像
Matlab仿真径向受压圆盘光弹图像-十步相移法 主要参数 % 定义圆盘参数 R 15; % 圆盘半径,单位:mm h 5; % 圆盘厚度,单位:mm P 300; % 径向受压载荷大小,单位ÿ…...
补偿电阻对ota零极点的影响
本文内容主要是关于补偿电阻对零极点产生的影响。 1.极点分析 该补偿电阻并不会影响在输出端的主极点,受影响的主要是镜像极点。 这里我们可以先单看电流镜部分,这个补偿电阻的作用在于将极点推向原来的两倍,从而达到增加带宽的目的[1]。 …...
C++单例模式跨DLL调用问题梳理
问题案例: 假设有这样一个单例模式的代码 //test.h header class Test { public:static Test &instance() {static Test ins;return ins;}void foo(); };void testFoo();//test.cpp source #include "test.h"void Test::foo() {printf("%p\n&q…...
Linux高并发服务器开发 第十天(man手册 系统调用 文件打开关闭 文件创建权限)
目录 1.文件IO 1.1man 手册 1.2系统调用 1.3操作函数 1.3.1打开文件 1.3.2关闭文件 1.4文件创建权限 1.文件IO 1.1man 手册 man man 可以查看。man手册共 9 卷。 可执行程序、shell命令。系统调用函数。(内核提供的函数)库函数第 5 卷。查看特殊…...
用CRD定义未来:解锁机器学习平台的无限可能
Kubernetes CustomResourceDefinition(CRD)详解 一、CRD 概述 CRD(CustomResourceDefinition,自定义资源定义)是 Kubernetes 提供的一种机制,用于用户自定义新的资源类型。CRD 扩展了 Kubernetes API&…...
A second-price auction
第二价格密封拍卖(A second - price auction)是一种常见的拍卖形式,以下是一个用收益矩阵(Payoff Matrix)来说明第二价格密封拍卖的例子: 假设有三个竞拍者:A、B、C,他们对一件古董…...
MacBook_Xcode_Swift雨燕
Swift Swift Swift Swift是苹果公司开发的现代化编程语言, 专为Apple平台设计。其简洁语法、类型安全、Optionals处理、Playgrounds交互式环境、泛型编程、协议与扩展、闭包功能、枚举与关联值、结构体与类的高效内存管理、异步编程的async/await语法、Swift Packa…...
力扣面试题 - 08.07.无重复字符串的排列组合 C语言解法 回溯递归dfs深度优先
题目: 无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。 示例 1: 输入:S "qwe"输出:["qwe", "qew", "wqe", "…...
数值分析速成复习笔记
请确保你有10hour的有效学习时间,保你拿90 证明部分 编程部分...
1.07 标准IO
1.思维导图 2.先编写以下结构体 struct Student { char name[20]; double math; double chinese; double english; double physical; double chemical; double…...
单片机实现模式转换
[任务] 要求通过单片机实现以下功能: 1.单片机有三种工作模式(定义全局变量MM表示模式,MM1,2,3表示三种不同的模式) LED控制模式 风扇控制模式 蜂鸣器控制模式 2.可以在某一个模式下通过拓展板KEY1按键控制设备 (按…...
JVM实战—OOM的定位和解决
1.如何对系统的OOM异常进行监控和报警 (1)最佳的解决方案 最佳的OOM监控方案就是:建立一套监控平台,比如搭建Zabbix、Open-Falcon之类的监控平台。如果有监控平台,就可以接入系统异常的监控和报警,可以设置当系统出现OOM异常&…...
GolangWeb开发- net/http模块
文章目录 Golang开发-案例整理汇总一、net/http介绍二、HTTP客户端Get请求Post请求三、HTTP服务端总结Golang开发经典案例,点击下方链接 Golang开发-案例整理汇总 一、net/http介绍 Go语言内置的net/http包提供了HTTP客户端和服务端的实现。 文档链接: https://pkg.go.dev/n…...
算法:线性查找
线性查找算法是一种简单的查找算法,用于在一个数组或列表中查找一个特定的元素。它从数组的第一个元素开始,逐个检查每个元素,直到找到所需的元素或搜索完整个数组。线性查找的时间复杂度为O(n),其中n是数组中的元素数量。 实现原理 从列表的第一个元素开始,逐个检查每个…...
基于 Boost.Asio 和 Boost.Beast 的异步 HTTP 服务器(学习记录)
已完成功能: 支持 GET 和 POST 请求的路由与回调处理。 解析URL请求。 单例模式 管理核心业务逻辑。 异步 I/O 技术和 定时器 控制超时。 通过回调函数注册机制,可以灵活地为不同的 URL 路由注册处理函数。 1. 项目背景 1.1 项目简介 本项目是一个基于…...
『SQLite』常见函数的使用
摘要:主要讲解SQLite中的常见函数,有聚合函数、数字函数、字符串函数、日期函数、类型转换函数等。 主要函数 聚合函数:count()、sum()、avg()、min()、max()字符串函数:length()、upper()、lower()、substr()、trim()日期和时间…...
win下搭建elk并集成springboot
一、ELK 是什么? ELK 实际上是三个工具的集合,Elasticsearch Logstash Kibana,这三个工具组合形成了一套实用、易用的监控架构,很多公司利用它来搭建可视化的海量日志分析平台。 ElasticSearch ElasticSearch 是一个基于 Lucen…...
ABAQUS柱状晶模型基于泰森多边形建模
建立柱状晶几何模型进行有限元分析有助于深入理解材料的微观结构与宏观性能之间的关系,为材料设计、制造工艺优化及失效预测提供了强有力的工具。本案例介绍采用AutoCAD基于泰森多边形算法生成柱状晶三维几何部件,并导入Abaqus有限元软件内建立包含晶粒及…...
MySQL InnoDB常用锁总结(行锁、间隙锁、临键锁、表锁)
在高并发数据库系统中,锁机制是保障数据一致性和事务隔离性的重要手段。MySQL 的 InnoDB 存储引擎提供了多种锁类型,包括行锁、间隙锁、临键锁和表锁。本文将详细介绍这些锁的原理、使用场景及其注意事项,并结合案例进行说明。 1. 表锁 概念…...
Flink系统知识讲解之:如何识别反压的源头
Flink系统知识之:如何识别反压的源头 什么是反压 Ufuk Celebi 在一篇古老但仍然准确的文章中对此做了很好的解释。如果您不熟悉这个概念,强烈推荐您阅读这篇文章。如果想更深入、更低层次地了解该主题以及 Flink 网络协议栈的工作原理,这里有…...
UE5行为树浅析
Tree 什么是树? 树是由节点或顶点和边组成的数据结构,没有任何循环。没有节点的树称为空树或空树。 非空的树由根节点和可能形成层次结构的多层附加节点组成。 树是一种数据结构树由点和有向边组成树是连通的,可达的树有执行顺序树没有环 …...
大模型测试-数飞机个数
时间是2025年1月7日,测试下各大网页端大模型的多模态识图能力。 测试题目 图片 问题 标记一下图里的飞机,并数一下飞机的个数 测试结果 千问qwen 在这张图片中,我可以看到总共12架飞机。以下是它们的位置标记:左上角跑道上有…...
Ubuntu挂载Windows 磁盘,双系统
首先我们需要在终端输入这个命令,来查看磁盘分配情况 lsblk -f 找到需要挂载的磁盘,检查其类型( 我的/dev/nvme2n1p1类型是ntfs,名字叫3500winData) 然后新建一个挂载磁盘的目录,我的是/media/zeqi/3500wi…...
快速上手:采用Let‘sEncrypt免费SSL证书配置网站Https (示例环境:Centos7.9+Nginx+Let‘sEncrypt)
1 关于Let’s Encrypt与Cerbot DNS验证 Let’s Encrypt 是一个提供 免费证书 的 认证机构。 Cerbot 是 Let’s Encrypt 提供的一个工具,用于自动化生成、验证和续订证书。 DNS验证是 Cerbot 支持的验证方式之一。相比 HTTP 验证或 TLS-ALPN 验证,DNS …...
【项目】修改远程仓库地址、报错jdk
一、修改远程仓库地址 进入你刚刚克隆到本地的仓库目录,执行以下命令来修改远程仓库的 URL,将其指向你自己的新仓库: cd 原仓库名 git remote set-url origin <你自己的新仓库的 Git 地址>二、运行报错 多数jdk版本问题 三、 知识图…...
.NET体系架构
引言 .NET是由微软开发的一个广泛应用的开发平台,旨在帮助开发者构建各种类型的应用程序,包括桌面应用、Web应用、移动应用和云服务。最初,.NET平台的构建主要集中在Windows环境上,但随着.NET Core和随后.NET 5及以上版本的推出&…...
MTK平台-- 无线AP隔离功能
前言: 无线AP上大都有一个选项:启用该功能后,连接到同一AP的无线终端之间不能互相通信,但该功能并不限制无线终端和有线终端之间的通信。 Hostapd参数ap_isolate,用于控制AP隔离,但hostapd本身并不实现这一功能,只是将该参数通过nl80211传递给mac80211,由mac80211来实…...
初学stm32 --- 电源监控
目录 STM32 电源监控介绍 上电/掉电复位POR/PDR(F1) 可编程电压检测器(PVD)(F1) PVD相关寄存器介绍(F1) 电源控制寄存器 PWR_CR 电源控制/状态寄存器 PWR_CSR PVD相关HAL库驱动介绍 PVD的使用步骤 …...
小程序组件 —— 28 组件案例 - 推荐商品区域 - 实现结构样式
这一节目标是实现底部推荐商品的结构和样式,由于这里要求横向滚动,所以需要使用上节介绍的 scroll-view 功能,并使用 scroll-x 属性支持横向滚动,推荐商品区域中的每一个商品是一个单独的 view,每个view 中需要写三个组…...
深入了解 SSL/TLS 协议及其工作原理
深入了解 SSL/TLS 协议及其工作原理 一. 什么是 SSL/TLS?二. SSL/TLS 握手过程三. SSL/TLS 数据加密与传输四. 总结 点个免费的赞和关注,有错误的地方请指出,看个人主页有惊喜。 作者:神的孩子都在歌唱 一. 什么是 SSL/TLS? 安全套接层&am…...
解决RuntimeError: No CUDA GPUs are available问题
今天运行之前可以正常运行的项目时,发现了以下问题: 接下来记录解决过程: 参考:os.environ[“CUDA_VISIBLE_DEVICES”]"2"的问题 因为代码中设置了选择了具体的GPU的型号,但是有可能没有这个GPU࿰…...
了解RabbitMQ中的Exchange:深入解析与实践应用
在分布式系统设计中,消息队列(Message Queue)扮演着至关重要的角色,而RabbitMQ作为开源消息代理软件的佼佼者,以其高性能、高可用性和丰富的功能特性,成为了众多开发者的首选。在RabbitMQ的核心组件中&…...
33.3K 的Freqtrade:开启加密货币自动化交易之旅
“ 如何更高效、智能地进行交易成为众多投资者关注的焦点。” Freqtrade 是一款用 Python 编写的免费开源加密货币交易机器人。它就像一位不知疲倦的智能交易助手,能够连接到众多主流加密货币交易所,如 Binance、Bitmart、Bybit 等(支…...
(概率论)区间估计 和 置信区间 、 假设检验
参考文章1:3分钟,看懂区间估计and置信区间 - 知乎 (zhihu.com) 1、点估计的定义: 2、区间估计的定义: 参考文章2:【概率论】- (1)区间估计 - 知乎 (zhihu.com) 这篇文章中的2中,2.1、2.2、2.3描述了需要用到…...
MBTiles 及爬取到发布
MBTiles :https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md 1.MBTiles是什么 MBTiles是一个在SQLite 数据库存储瓦片地图数据的标准,该标准的目的是即时传输和使用数据。 作为一个容器格式,MBTiles可以存储任何瓦片数据,…...
uniapp使用chooseLocation安卓篇
本文章全部以高德地图为例 代码 <view class"bottom"><button click"choose">定位</button> </view> choose() {uni.chooseLocation({success: function(res) {console.log(位置名称: res.name);console.log(详细地…...
el-cascader 树状选择-点击父级禁用子级
背景:项目上需要实现树状选择,点击父级禁用子级的功能,element组件本身没有该配置项说明:需要实现几个功能点:点击父级禁用子级;再次点击取消禁用;仅回填所选级;上下级不关联实现代码…...
力扣经典题目之219. 存在重复元素 II
今天继续给大家分享一道力扣的做题心得今天这道题目是 219. 存在重复元素 II,我使用 hashmap 的方法来解题 题目如下,题目链接:219. 存在重复元素 II 1,题目分析 此题目给我们了一个整数数组 nums 和一个整数 k ,需要…...
微服务保护—Sentinel快速入门+微服务整合 示例: 黑马商城
1.微服务保护 微服务保护是确保微服务架构可靠、稳定和安全的策略与技术。 在可靠性上,限流是控制进入微服务的请求数量,防止流量过大导致服务崩溃。比如电商促销时对商品详情服务进行流量限制。熔断是当被调用的微服务故障过多或响应过慢时,…...
Wireshark 学习笔记1
1.wireshark是什么 wireshark是一个可以进行数据包的捕获和分析的软件 2.基本使用过程 (1)选择合适的网卡 (2)开始捕获数据包 (3)过滤掉无用的数据包 (4)将捕获到的数据包保存为文件…...
voice agent实现方案调研
前言 目前语音交互主要的实现大体有两种: 级联方案,指的是,大规模语言模型 (LLM)、文本转语音 (TTS) 和语音转文本 (STT),客户的话通过vad断句到STT的语音转文本,经过大模型进行生成文本,生成文本后通过TTS进行回复给用户。(主流方案)端到端的方案,开发者无需再…...
pgpool配置安装之服务器的配置
第 1 章.服务器配置 1.1. 设置参数 1.1.1. 参数名称和值 所有参数名称均不区分大小写。每个参数都采用 值为以下五种类型之一:boolean、string、integer、floating point、 或枚举 (enum)。类型决定了设置 参数: 布尔…...
C++实现银行排队系统
网上看到的设计要求: 基本效果已经实现,希望大家帮忙指点指点。 程序中的一些基本模块 程序处理中的一些流程图 程序运行结果如下图: 程序代码如下: #include <iostream> #include <string> #include <random&g…...
UI自动化测试保姆级教程①
欢迎来到阿妮莫的学习小屋慢也好,步子小也好,在往前走就好 目录 自动化测试 简介 作用 分类 优缺点 优点 缺点(误区) UI自动化测试 自动化测试使用场景 自动化测试实现时间 Selenium框架 特点 Web自动化测试环境部署 Selenium包安装 浏览…...
多行输入模式(dquote> 提示符)double quote(双引号)
文章目录 1、引号不匹配具体原因解决办法如何避免此问题 2、double quote(双引号)出现原因解决办法预防措施 ~/Downloads/productqualification-develop git:[main] git commit -m "漏添加到暂存区的代码“ dgqdgqdeMac-mini productqualification-…...
【Uniapp-Vue3】原生事件监听及组件内置事件处理
如果我们想给元素添加一个事件就要使用到v-on,也可以简写为: <标签名 v-on:事件名"函数"></标签名> 或简写为 <标签名 事件名"函数"></标签名> 比如我们想要实现点击一下元素,num就1,…...