学习JavaEE的日子 Day30 线程安全

Day30

1.作业

1.1 线程类解决

1.计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。

注意:使用线程类的方式解决该需求

public class Test01 {public static void main(String[] args) throws InterruptedException {//创建数组int[] arr = new int[20000];//初始化数组数据 -- {1,2,3,....,20000}for (int i = 0; i < arr.length; i++) {arr[i] = i+1;}//创建线程MyThread t1 = new MyThread(0, 5000, arr);MyThread t2 = new MyThread(5000, 10000, arr);MyThread t3 = new MyThread(10000, 15000, arr);MyThread t4 = new MyThread(15000, 20000, arr);//启动线程t1.start();t2.start();t3.start();t4.start();//问题出现原因:四个子线程还没有运行完毕,就被主线程抢到CPU资源了//解决思路:让四个子线程执行完毕后,主线程才能执行 --- 主线程阻塞!!!//解决方案一:
//		Thread.sleep(6);//解决方案二:
//		while(t1.isFlag() || t2.isFlag() || t3.isFlag() || t4.isFlag()){}//解决方案三:t1.join();t2.join();t3.join();t4.join();//合并子线程的运行结果int result = t1.getSum() + t2.getSum() + t3.getSum() + t4.getSum();System.out.println(result);}
}
public class MyThread extends Thread{private int startIndex;private int endIndex;private int[] arr;public MyThread(int startIndex, int endIndex, int[] arr) {this.startIndex = startIndex;this.endIndex = endIndex;this.arr = arr;}private int sum;private boolean flag = true;@Overridepublic void run() {for (int i = startIndex; i < endIndex; i++) {sum += arr[i];}flag = false;}public int getSum() {return sum;}public boolean isFlag() {return flag;}
}

1.2 任务类解决

注意:使用任务类的方式解决该需求

public class Test01 {public static void main(String[] args) throws InterruptedException {//创建数组int[] arr = new int[20000];//初始化数组数据 -- {1,2,3,....,20000}for (int i = 0; i < arr.length; i++) {arr[i] = i+1;}//创建任务Task task1 = new Task(0, 5000, arr);Task task2 = new Task(5000, 10000, arr);Task task3 = new Task(10000, 15000, arr);Task task4 = new Task(15000, 20000, arr);//创建线程Thread t1 = new Thread(task1);Thread t2 = new Thread(task2);Thread t3 = new Thread(task3);Thread t4 = new Thread(task4);//启动线程t1.start();t2.start();t3.start();t4.start();//问题出现原因:四个子线程还没有运行完毕,就被主线程抢到CPU资源了//解决思路:让四个子线程执行完毕后,主线程才能执行 --- 主线程阻塞!!!//解决方案一:
//		Thread.sleep(6);//解决方案二:
//		while(task1.isFlag() || task2.isFlag() || task3.isFlag() || task4.isFlag()){}//解决方案三:t1.join();t2.join();t3.join();t4.join();//合并任务的运行结果int result = task1.getSum() + task2.getSum() + task3.getSum() + task4.getSum();System.out.println(result);}
}
public class Task implements Runnable{private int startIndex;private int endIndex;private int[] arr;public Task(int startIndex, int endIndex, int[] arr) {this.startIndex = startIndex;this.endIndex = endIndex;this.arr = arr;}private int sum;private boolean flag = true;@Overridepublic void run() {for (int i = startIndex; i < endIndex; i++) {sum += arr[i];}flag = false;}public int getSum() {return sum;}public boolean isFlag() {return flag;}}

1.线程安全

1.1 线程类解决

1.1.1 同步代码块

线程安全 – 加锁

注意:要想多个线程互斥住,就必须使用同一把锁(对象)!!! 重要

synchronized

同步代码块:

synchronized(锁对象){//自动上锁

​ …想要互斥的代码…

}//自动解锁

Lock

需求:铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,请编写多线程程序来模拟这个效果

窗口001正在销售第1张票

窗口001正在销售第2张票

窗口002正在销售第3张票

。。。

窗口002正在销售第1000张票

窗口002票已售完

窗口001票已售完

窗口003票已售完

注意:使用线程类的方式解决该需求

问题一:三个窗口各卖1000张票,一共卖了3000张

出现原因:allTicket和curTicket是run方法的局部变量,三个线程抢到CPU资源后,都会调用run方法,run方法被调用了3次,所以卖了3000张票

解决方案:将allTicket和curTicket设置为静态变量,让三个线程共享

问题二:有些票没有卖,有些票卖了重票

出现原因:当前线程抢到CPU资源后做了票的自增,但是还没来得及输出,时间片到了就退出CPU资源,然后其他线程抢到CPU资源了

解决方案:当前线程抢到CPU资源后,票的自增和输出执行完毕才能切换到其他线程运行 – 加锁

问题三:多卖了票

出现原因:curTicket到了临界点(999),三个线程都可以进判断,然后上锁

解决方案:在锁中再次判断

注意:锁对象使用static非常不好

public class Test01 {public static void main(String[] args) {MyThread t1 = new MyThread("001");MyThread t2 = new MyThread("002");MyThread t3 = new MyThread("003");t1.start();t2.start();t3.start();}
}
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;private static Object obj = new Object();public MyThread(String name) {super(name);}@Overridepublic void run() {while(curTicket < allTicket){//都是锁对象//synchronized (String.class) {//synchronized ("abc") {synchronized (obj) {if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}if(curTicket >= allTicket){System.out.println("窗口" +  Thread.currentThread().getName() + "票已经售完");}}}}
}
同步代码块解决数据安全问题【应用】

安全问题出现的条件

- 是多线程环境

- 有共享数据

- 有多条语句操作共享数据

如何解决多线程安全问题呢?

- 基本思想:让程序没有安全问题的环境

怎么实现呢?

- 把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可

- Java提供了同步代码块的方式来解决

同步代码块格式:

synchronized(任意对象) {

多条语句操作共享数据的代码

}

synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看成是一把锁

同步的好处和弊端

- 好处:解决了多线程的数据安全问题

- 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

1.1.2 同步方法

synchronized

同步代码块:

synchronized(锁对象){//自动上锁

​ …想要互斥的代码…

}//自动解锁

同步方法

同步方法 – 成员同步方法:

注意:锁对象 -> this

public synchronized void method(){//自动上锁

…想要互斥的代码…

}//自动解锁

同步方法 – 静态同步方法:

注意:锁对象 -> 类.class

public static synchronized void method(){//自动上锁

…想要互斥的代码…

}//自动解锁

public class Test01 {public static void main(String[] args) {MyThread t1 = new MyThread("001");MyThread t2 = new MyThread("002");MyThread t3 = new MyThread("003");t1.start();t2.start();t3.start();}
}
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;public MyThread(String name) {super(name);}@Overridepublic void run() {while(curTicket < allTicket){method();}}//一定是要加static,因为不加锁对象是this,锁不住//锁对象:MyThread.classpublic static synchronized void method(){if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}if(curTicket >= allTicket){System.out.println("窗口" +  Thread.currentThread().getName() + "票已经售完");}}}
同步方法解决数据安全问题【应用】

同步方法的格式

同步方法:就是把synchronized关键字加到方法上

修饰符 synchronized 返回值类型 方法名(方法参数) {

方法体;

}

同步方法的锁对象是什么呢?

this

静态同步方法

同步静态方法:就是把synchronized关键字加到静态方法上

修饰符 static synchronized 返回值类型 方法名(方法参数) {

方法体;

}

1.1.3 Lock锁

Lock

//锁对象

Lock lock = new ReentrantLock();

//要加 try…catch…

lock.lock();//手动上锁 写在 synchronized的位置,代替

…想要互斥的代码…

lock.unlock();//手动解锁

public class Test01 {public static void main(String[] args) {MyThread t1 = new MyThread("001");MyThread t2 = new MyThread("002");MyThread t3 = new MyThread("003");t1.start();t2.start();t3.start();}
}
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;//必须是静态的,因为有三个对象,让线程所有对象都共享private static Lock lock = new ReentrantLock();public MyThread(String name) {super(name);}@Overridepublic void run() {while(curTicket < allTicket){lock.lock();//手动上锁try {if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}if(curTicket >= allTicket){System.out.println("窗口" +  Thread.currentThread().getName() + "票已经售完");}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();//手动解锁}}}}

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化

ReentrantLock构造方法

ReentrantLock():创建一个ReentrantLock的实例

加锁解锁方法

lock():获得锁

unlock():释放锁

1.2 任务类解决

1.2.1 同步代码块

需求:铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,请编写多线程程序来模拟这个效果

窗口001正在销售第1张票

窗口001正在销售第2张票

窗口002正在销售第3张票

。。。

窗口002正在销售第1000张票

窗口002票已售完

窗口001票已售完

窗口003票已售完

注意:使用任务类的方式解决该需求

(与上面的不一样)

问题一:三个窗口各卖1000张票,一共卖了3000张

出现原因:三个线程抢到CPU资源后都会调用run方法,curTicket和allTicket都是run方法里的局部变量,所以会调用3次

解决思路:curTicket和allTicket设置为成员属性,三个线程共用同一个任务

问题二:有些票没有卖,有些票卖了重票

出现原因:当前线程抢到CPU资源后做了票的自增,但是还没来得及输出,时间片到了就退出CPU资源,然后其他线程抢到CPU资源了

解决方案:当前线程抢到CPU资源后,票的自增和输出执行完毕才能切换到其他线程运行 – 加锁

问题三:多卖了票

出现原因:curTicket到了临界点(999),三个线程都可以进判断,然后上锁

解决方案:在锁中再次判断

public class Test01 {public static void main(String[] args) {Task task = new Task();Thread t1 = new Thread(task, "001");Thread t2 = new Thread(task, "002");Thread t3 = new Thread(task, "003");t1.start();t2.start();t3.start();}
}
public class Task implements Runnable{private int allTicket = 1000;private int curTicket = 0;@Overridepublic void run() {while(curTicket < allTicket){synchronized (this) {//使用this,不用objif(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}}}System.out.println("窗口" + Thread.currentThread().getName() + "票已售完");}}
1.2.2 同步方法
public class Test01 {public static void main(String[] args) {Task task = new Task();Thread t1 = new Thread(task, "001");Thread t2 = new Thread(task, "002");Thread t3 = new Thread(task, "003");t1.start();t2.start();t3.start();}
}
public class Task implements Runnable{private int allTicket = 1000;private int curTicket = 0;@Overridepublic void run() {while(curTicket < allTicket){method();}System.out.println("窗口" + Thread.currentThread().getName() + "票已售完");}//用成员同步方法public synchronized void method(){if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}}}
1.2.3 Lock锁

Lock锁要加try…catch

public class Test01 {public static void main(String[] args) {Task task = new Task();Thread t1 = new Thread(task, "001");Thread t2 = new Thread(task, "002");Thread t3 = new Thread(task, "003");t1.start();t2.start();t3.start();}
}
public class Task implements Runnable{private int allTicket = 1000;private int curTicket = 0;private Lock lock = new ReentrantLock();@Overridepublic void run() {while(curTicket < allTicket){lock.lock();try {if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}System.out.println("窗口" + Thread.currentThread().getName() + "票已售完");}}

注意:一般解决需求,使用任务类,更灵活

简答题

关于 Java多线程,在面试的时候,问的比较多的就是①悲观锁和乐观锁( 具体可以看我的这篇文章:面试必备之乐 观锁与悲观锁)、②synchronized和lock区别以及volatile和synchronized的区别**,③可重入锁与非可重入锁的区 别④多线程是解决什么问题的⑤线程池解决什么问题⑥线程池的原理、**⑦线程池使用时的注意事项、⑧AQS原理、⑨ReentranLock源码,设计原理,整体过程等等问题。

面试官在多线程这一部分很可能会问你有没有在项目中实际使用多线程的经历。所以,如果你在你的项目中有实际使用Java多线程的经历 的话,会为你加分不少哦!

1.什么是线程安全?

线程安全就是说多线程访问同一代码,不会产生不确定的结果:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量 的值也和预期的是一样的,就是线程安全的。

在多线程环境中,当各线程不共享数据的时候,即都是私有(private)成员,那么一定是线程安全的,但这种情况并不多见,在多数情况下需要共享数据,这时就需要进行适当的同步控制了。

线程安全一般都涉及到synchronized, 就是一段代码同时只能有一个线程来操作,不然中间过程可能会产生不可预制的结果。

2…说一说自己对于synchronized关键字的了解

synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。

另外,在 Java 早期版本中,synchronized属于重量级锁,效率低下,因为监视器锁(monitor)是依赖于底层的操作系统的 Mutex Lock 来实现的,Java 的线程是映射到操作系统的原生线程之上的。如果要挂起或者唤醒一个线程,都需要操作系统帮忙完成,而操作系统实现线程之间的切换时需要从用户态 转换到内核态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高,这也是为什么早期的synchronized 效率低的原因。庆幸的是在 Java 6 之后 Java 官方对从 JVM 层面对synchronized 较大优 化,所以现在的 synchronized 锁效率也优化得很不错了。JDK1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。

3…说说自己是怎么使用synchronized关键字,在项目中用到了吗?

synchronized关键字最主要的三种使用方式:

修饰实例方法: 作用于当前对象实例加锁,进入同步代码前要获得当前对象实例的锁

修饰静态方法: 也就是给当前类加锁,会作用于类的所有对象实例,因为静态成员不属于任何一个实例对象,是类成员( static 表明这是该类的一个静态资源,不管new了多少个对象,只有一份)。所以如 果一个线程A调用一个实例对象的非静态 synchronized 方法,而线程B需要调用这个实例对象所属类的 静态 synchronized 方法,是许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁 是当前类的锁,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。

修饰代码块: 指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

总结: synchronized 关键字加到 static 静态方法和 synchronized(class)代码块上都是是给 Class 类上锁。synchronized 关键字加到实例方法上是给对象实例上锁。尽量不要使用 synchronized(String a) 因 为JVM中,字符串常量池具有缓存功能!

下面我已一个常见的面试题为例讲解一下 synchronized 关键字的具体使用。

面试中面试官经常会说:“单例模式了解吗?来给我手写一下!给我解释一下双重检验锁方式实现单例模式的原理呗!”

双重校验锁实现对象单例(线程安全)

public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}

另外,需要注意 uniqueInstance 采用 volatile 关键字修饰也是很有必要。

uniqueInstance 采用 volatile 关键字修饰也是很有必要的, uniqueInstance = new Singleton(); 这段代码其实是分为三步执行:

1.为 uniqueInstance 分配内存空间

2.初始化 uniqueInstance

3.将 uniqueInstance 指向分配的内存地址

但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1->3->2。指令重排在单线程环境下不会出先问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T1 执行了 1 和 3, 此时 T2 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。

使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。

4.讲一下 synchronized*关键字的底层原理

synchronized 关键字底层原理属于 JVM 层面。

synchronized 同步语句块的情况

public class SynchronizedDemo {
public void method() {
synchronized (this) {
System.out.println("synchronized 代码块");
}
}
}

在cmd控制台通过 javap 命令查看 SynchronizedDemo 类的相关字节码信息:

synchronized 同步语句块的实现使用的是 monitorenter monitorexit 指令,其中 monitorenter **指令指向同步代码块的开始位置,**monitorexit 指令则指明同步代码块的结束位置。

当执行 monitorenter 指令时,线程试图获取锁也就是获取 monitor(monitor对象存在于每个Java对象的对象头中,synchronized 锁便是通过这种方式获取锁的,也是为什么Java中任意对象可以作为锁的原因) 的持有权.当计数器为0则可以成功获取,获取后将锁计数器设为1也就是加1。相应的在执行 monitorexit 指令后,将锁计数器设为0,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等 待,直到锁被另外一个线程释放为止。

Java中synchronized和ReentrantLock有什么不同?

相似点:

这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一 个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的.

区别:

这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需 要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成。

Synchronized进过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。

由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized, ReentrantLock类提供了一些高级功能,主要有以下3项:

1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。

2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。

3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定多个对象。

谈谈synchronized和ReenTrantLock的区别

① 两者都是可重入锁

两者都是可重入锁。“可重入锁”概念是:自己可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。同一个线程每次获取锁,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。

synchronized 依赖于 JVM ReenTrantLock 依赖于 API

synchronized 是依赖于 JVM 实现的,前面我们也讲到了 虚拟机团队在 JDK1.6 为 synchronized 关键字进行了很多优化,但是这些优化都是在虚拟机层面实现的,并没有直接暴露给我们。ReenTrantLock 是 JDK 层面实现的(也就是 API 层面,需要 lock() 和 unlock 方法配合 try/finally 语句块来完成),所以我们可以通过查看它的源代码,来看它是如何实现的。

ReenTrantLock synchronized 增加了一些高级功能

相比synchronized,ReenTrantLock增加了一些高级功能。主要来说主要有三点:①等待可中断;②可实现公平锁;

③可实现选择性通知(锁可以绑定多个条件)

ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。

ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。ReenTrantLock默认情况是非公平的,可以通过 ReenTrantLock类的ReentrantLock(boolean fair) 构造方法来制定是否是公平的。

synchronized关键字与wait()和notify/notifyAll()方法相结合可以实现等待/通知机制,ReentrantLock类当然也可以实现,但是需要借助于Condition接口与newCondition() 方法。Condition是JDK1.5之后才有的,它具有很好的灵活性,比如可以实现多路通知功能也就是在一个Lock对象中可以创建多个Condition实例(即对象监视 器),线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活。 在使用notify/notifyAll()方法进行通知时,被通知的线程是由JVM选择的,用ReentrantLock类结合Condition实例可以实现“选择性通知” ,这个功能非常重要,而且是Condition接口默认提供的。而synchronized关键字就相当于整个Lock对象中只有一个Condition实例,所有的线程都注册在它一个身上。如果 执行notifyAll()方法的话就会通知所有处于等待状态的线程这样会造成很大的效率问题,而Condition实例的 signalAll()方法 只会唤醒注册在该Condition实例中的所有等待线程。如果你想使用上述功能,那么选择ReenTrantLock是一个不错的选择。

④ 性能已不是选择标准

总结

1.评讲作业

2.买票的案例 – 线程安全 (重要)
1.完全掌握卖票案例
2.理解对象内存结构 - https://blog.csdn.net/weixin_44606481/article/details/134802419

3.线程安全 — 买票案例
synchronized代码块
synchronized方法(成员同步方法、静态同步方法)
Lock锁
注意:
1.加锁的方式
2.锁对象(多个线程去操作同一把锁才能互斥住)

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

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

相关文章

AI大语言模型工程师学习路线

文章目录 运行LLMSLLM APIS开源的大语言模型Prompt engineering1. 明确目标2. 理解模型能力3. 使用示例4. 精确和具体的指令5. 考虑上下文6. 避免偏见和不准确的信息7. 测试和迭代8. 使用模板9. 考虑多语言能力10. 注意伦理和合规性结构化输出1. 使用明确的提示(Prompts)2. 采…

什么是自然语言处理(NLP)?自然语言处理(NLP)的概述

什么是自然语言处理&#xff1f; 自然语言处理&#xff08;NLP&#xff09;是人工智能&#xff08;AI&#xff09;和计算语言学领域的一个分支&#xff0c;它致力于使计算机能够理解、解释和生成人类语言。随着技术的发展&#xff0c;NLP已经从简单的模式匹配发展到了能够理解…

Ceph——部署

Ceph简介 Ceph是一款开源的 SDS 分布式存储&#xff0c;它具备极高的可用性、扩展性和易用性&#xff0c;可用于存 储海量数据 Ceph的存储节点可部署在通用服务器上&#xff0c;这些服务器的 CPU 可以是 x86 架构的&#xff0c;也可以 是 ARM 架构的。 Ceph 存储节点之间相互…

政安晨:【深度学习神经网络基础】(一)—— 逐本溯源

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 与计算机一样的古老历史 神经网络的出现可追溯到20世纪40年…

ubuntu22.04系统安装Opencv4.8.0+Opencv-contrib4.8.0

一、安装下载所需工具 1.打开终端&#xff0c;输入以下命令来更新软件源&#xff1a; sudo apt-get update 2.安装wget&#xff1a; sudo apt-get install wget 3.下载opencv和opencv-contrib包&#xff1a; wget -O opencv-4.8.0.zip https://github.com/opencv/opencv/…

【漏洞复现】网络验证系统getInfo接口处存在SQL注入漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

Remote Desktop Manager for Mac:远程桌面管理软件

Remote Desktop Manager for Mac&#xff0c;是远程桌面管理的理想之选。它集成了多种远程连接技术&#xff0c;无论是SSH、RDP还是VNC&#xff0c;都能轻松应对&#xff0c;让您随时随地安全访问远程服务器和工作站。 软件下载&#xff1a;Remote Desktop Manager for Mac下载…

【性能优化】 【回溯】 【字符串】1307. 口算难题

作者推荐 视频算法专题 本文涉及知识点 数学 回溯 字符串 性能优化 LeetCode1307. 口算难题 给你一个方程&#xff0c;左边用 words 表示&#xff0c;右边用 result 表示。 你需要根据以下规则检查方程是否可解&#xff1a; 每个字符都会被解码成一位数字&#xff08;0 - …

云原生(六)、CICD - Jenkins快速入门

Jenkuns快速入门 一、CICD概述 CICD是持续集成&#xff08;Continuous Integration&#xff09;和持续部署&#xff08;Continuous Deployment&#xff09;的缩写。它是软件开发中的一种流程和方法论&#xff0c;旨在通过自动化的方式频繁地将代码集成到共享存储库中&#xf…

策略路由-IP-Link-路由协议简介

策略路由 策略路由和路由策略的不同 1.策略路由的操作对象是数据包&#xff0c;在路由表已经产生的情况下&#xff0c;不按照路由表进行转发&#xff0c;而是根据需要&#xff0c;依照某种策略改变数据包的转发路径 2.路由策略的操作对象是路由信息。路由策略的主要实现了路…

关于LLM的简单赘述

关于LLM的简单赘述 在线大模型开源大模型GPT系列模型先进模型特性大模型未来发展最重要的两个趋势 在线大模型 以 OpenAIGPT 系列为代表的大模型&#xff0c;只提供在线调用方法&#xff0c;无本地硬件要求&#xff0c;但调用需要“按量计费”(以及有网络限制)。 GPT模型谷歌…

nginx代理服务后,有关文件的操作无法执行,nginx代理jupyter或为知笔记后无法创建文件及文件夹,无法操作文件

nginx配置 server {listen 18001; # 修改转发的接口listen [::]:18001; # 修改转发的接口server_name _;root /usr/share/nginx/html;location / {proxy_pass http://127.0.0.1:7777; # 指定自己服务地址proxy_set_header Host $host;}# Load configurat…

服务器监控软件夜莺采集监控(三)

文章目录 一、采集器插件1. exec插件2. rabbitmq插件3. elasticsearch插件 二、监控仪表盘1. 系统信息2. 数据服务3. NginxMQ4. Docker5. 业务日志 一、采集器插件 1. exec插件 input.exec/exec.toml [[instances]] commands ["/home/monitor/categraf/scripts/*.sh&q…

【深度学习】图片预处理,分辨出模糊图片

ref:https://pyimagesearch.com/2015/09/07/blur-detection-with-opencv/ 论文 ref:https://www.cse.cuhk.edu.hk/leojia/all_final_papers/blur_detect_cvpr08.pdf 遇到模糊的图片&#xff0c;还要处理一下&#xff0c;把它挑出来&#xff0c;要么修复&#xff0c;要么弃用。否…

信号处理--情绪分类数据集DEAP预处理(python版)

关于 DEAP数据集是一个常用的情绪分类公共数据&#xff0c;在日常研究中经常被使用到。如何合理地预处理DEAP数据集&#xff0c;对于后端任务的成功与否&#xff0c;非常重要。本文主要介绍DEAP数据集的预处理流程。 工具 图片来源&#xff1a;DEAP: A Dataset for Emotion A…

【深度学习】深度学习md笔记总结第2篇:TensorFlow介绍,学习目标【附代码文档】

深度学习笔记完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;深度学习课程&#xff0c;深度学习介绍要求,目标,学习目标,1.1.1 区别,学习目标,学习目标。TensorFlow介绍&#xff0c;2.4 张量学习目标,2.4.1 张量(Tensor),2.4.2 创建张量的指令,2.4.3 张量…

Python 从0开始 一步步基于Django创建项目(11)注册新用户

1、修改C:\D\Python\Python310\study\snap_gram\users路径下的urls.py 添加‘注册新用户’URL。 #注册新用户 path(register/,views.register,nameregister), 2、修改C:\D\Python\Python310\study\snap_gram\users路径下的views.py 编写URL对应的视图函数register。 def r…

02.percona Toolkit工具pt-archiver命令实践

1.命令作用 Percona Toolkit有的32个命令&#xff0c;可以分为7大类 工具类别 工具命令 工具作用 备注 开发类 pt-duplicate-key-checker 列出并删除重复的索引和外键 pt-online-schema-change 在线修改表结构 pt-query-advisor 分析查询语句&#xff0c;并给出建议&#x…

Lua热更新(xlua)

发现错误时检查是否:冒号调用 只需要导入asset文件夹下的Plugins和Xlua这两个文件即可,别的不用导入 生成代码 和清空代码 C#调用lua using Xlua; 需要引入命名空间 解析器里面执行lua语法 lua解析器 LuaEnv 单引号是为了避免引号冲突 第二个参数是报错时显示什么提示…

【Java程序设计】【C00389】基于(JavaWeb)Springboot的校园疫情防控系统(有论文)

基于&#xff08;JavaWeb&#xff09;Springboot的校园疫情防控系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过…