当前位置: 首页 > news >正文

【Java学习笔记】多线程与线程池

多线程与线程池

    • 一、多线程安全与应用
      • 1、程序、进程与线程的关系
      • 2、创建多线程的三种方式
        • (1)继承Thread类创建线程【不推荐】
        • (2)实现Runnable接口创建线程
        • (3)Callable接口创建线程
      • 3、线程的生命周期
      • 4、初识线程同步并使用sychronized实现线程同步
        • (1)初识线程同步
        • (2)sychronized的锁对象
      • 5、死锁产生的原因与解决方式
      • 6、初识线程池及其基本使用
        • (1)Runnable接口的弊端:
        • (2)线程复用的理念
          • ThreadPool线程池
          • JUC支持的线程池种类
    • 二、线程池
      • 1、线程池——治理线程的最大法宝
        • (1)什么是“池”
        • (2)线程池
        • (3)线程池适合应用的场合
      • 2、创建和停止线程池:
      • 3、线程池应该手动创建还是自动创建:
        • (1)四种线程池自动创建弊端
        • (2)正确的创建线程池的方法:
        • (3)线程池里的线程数量设定为多少比较合适:
        • **(4)常见线程池的特点:**
      • 4、拒绝策略与钩子方法
      • 5、线程池实现原理
      • 6、 **线程池五种状态:**
    • 三、ThreadLocal
      • 2、典型场景2
      • 3、ThreadLocal的两个作用
      • **4、ThreadLocal主要方法:**
      • 5、Thread、ThreadLocal以及ThreadLocalMap三者之间的关系
      • 6、ThreadLocal注意点
        • 1、内存泄漏
        • 2、Value的泄漏
        • 3、如何避免内存泄漏

一、多线程安全与应用

1、程序、进程与线程的关系

进程是程序运行的实例;
当一个程序执行进入内存运行时,即变成一个进程;
进程的资源是彼此隔离的,其他进程不允许访问
线程是进程内执行的“任务”;
线程是进程内的一个“基本任务”,每个线程都有自己的功能,是CPU分配与调度的基本单位;
一个进程内可以包含多个线程,反之一个线程只能隶属于某一个线程;
进程内至少拥有一个“线程”,这个线程叫“主线程”,主线程消亡则进程结束;
单核CPU通过时间片使所有线程达到一个并发执行的效果;
多核CPU达到并行执行的效果;

2、创建多线程的三种方式

(1)继承Thread类创建线程【不推荐】

package org.example;import java.util.Random;public class ThreadExample1 {class Runner extends Thread {@Overridepublic void run() {Integer speed = new Random().nextInt(10);for (int i = 1; i <= 10; i++) {System.out.println("第" + i + "秒:" + this.getName() + "跑到:" + (i * speed));}}}public void start() {Runner runnerA = new Runner();runnerA.setName("参赛者A");Runner runnerB = new Runner();runnerB.setName("参赛者B");runnerA.start();runnerB.start();}// 主线程存在,进程存在,主线程消失,进程消失public static void main(String[] args) {new ThreadExample1().start();}
}

当调用thread.start()方法时,线程对象A和B中的run方法执行权移交给了操作系统,由操作系统的线程调度策略来决定先执行哪个方法

(2)实现Runnable接口创建线程

package org.example;import java.util.Random;public class ThreadExample2 {class Runner implements Runnable {@Overridepublic void run() {Integer speed = new Random().nextInt(10);for (int i = 1; i <= 10; i++) {System.out.println("第" + i + "秒:" + Thread.currentThread().getName() + "跑到:" + (i * speed));}}}public void start() {Runner runnerA = new Runner();Thread threadA = new Thread(runnerA);threadA.setName("参赛者A");Runner runnerB = new Runner();Thread threadB = new Thread(runnerB);threadB.setName("参赛者B");threadA.start();threadB.start();}// 主线程存在,进程存在,主线程消失,进程消失public static void main(String[] args) {new ThreadExample2().start();}
}

(3)Callable接口创建线程

package org.example;import java.util.Random;
import java.util.concurrent.*;public class ThreadExample3 {// callable线程执行后将结果返回class Runner implements Callable<Integer> {public String name;@Overridepublic Integer call() throws Exception {Integer speed = new Random().nextInt(10);Integer result = 0;for (int i = 1; i <= 10; i++) {System.out.println("第" + i + "秒:" + this.name + "跑到:" + (i * speed));result += i * speed;}return result;}}public void start() throws ExecutionException, InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(3);Runner threadA = new Runner();threadA.name = "参赛者A";Runner threadB = new Runner();threadB.name = "参赛者B";Runner threadC = new Runner();threadC.name = "参赛者C";Future<Integer> submit1 = executorService.submit(threadA);Future<Integer> submit2 = executorService.submit(threadB);Future<Integer> submit3 = executorService.submit(threadC);executorService.shutdown();System.out.println(threadA.name + "累计跑了" + submit1.get() + "米");System.out.println(threadB.name + "累计跑了" + submit2.get() + "米");System.out.println(threadC.name + "累计跑了" + submit3.get() + "米");}// 主线程存在,进程存在,主线程消失,进程消失public static void main(String[] args) throws ExecutionException, InterruptedException {new ThreadExample3().start();}
}

3、线程的生命周期

Thread类定义的线程六种状态:

public enum State {/*** Thread state for a thread which has not yet started.*/NEW,/*** Thread state for a runnable thread.  A thread in the runnable* state is executing in the Java virtual machine but it may* be waiting for other resources from the operating system* such as processor.*/RUNNABLE,/*** Thread state for a thread blocked waiting for a monitor lock.* A thread in the blocked state is waiting for a monitor lock* to enter a synchronized block/method or* reenter a synchronized block/method after calling* {@link Object#wait() Object.wait}.*/BLOCKED,/*** Thread state for a waiting thread.* A thread is in the waiting state due to calling one of the* following methods:* <ul>*   <li>{@link Object#wait() Object.wait} with no timeout</li>*   <li>{@link #join() Thread.join} with no timeout</li>*   <li>{@link LockSupport#park() LockSupport.park}</li>* </ul>** <p>A thread in the waiting state is waiting for another thread to* perform a particular action.** For example, a thread that has called {@code Object.wait()}* on an object is waiting for another thread to call* {@code Object.notify()} or {@code Object.notifyAll()} on* that object. A thread that has called {@code Thread.join()}* is waiting for a specified thread to terminate.*/WAITING,/*** Thread state for a waiting thread with a specified waiting time.* A thread is in the timed waiting state due to calling one of* the following methods with a specified positive waiting time:* <ul>*   <li>{@link #sleep Thread.sleep}</li>*   <li>{@link Object#wait(long) Object.wait} with timeout</li>*   <li>{@link #join(long) Thread.join} with timeout</li>*   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>*   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>* </ul>*/TIMED_WAITING,/*** Thread state for a terminated thread.* The thread has completed execution.*/TERMINATED;}

4、初识线程同步并使用sychronized实现线程同步

(1)初识线程同步

代码中的同步机制:

  • sychronized(同步锁)关键字的作用就是利用一个特定的对象设置一个锁(绣球),在多线程(游客)并发访问的时候,同时只允许一个线程(游客)可以获得这个锁,执行特定的代码(迎娶新娘)。执行后释放锁,继续由其他线程争抢。

(2)sychronized的锁对象

  • sychronized代码块:任意对象即可
  • sychronized方法:this当前对象【实际使用更多】
  • sychronized静态方法:该类的字节码对象
package org.example;public class SyncSample {class Printer {Object lock = new Object();public void print() throws InterruptedException {// 代码块synchronized (lock) {Thread.sleep(1000);System.out.println("你");Thread.sleep(1000);System.out.println("好");Thread.sleep(1000);System.out.println("北");Thread.sleep(1000);System.out.println("京");}}// 方法【实际使用更广泛】public synchronized void print2() throws InterruptedException {// 代码块Thread.sleep(1000);System.out.println("你");Thread.sleep(1000);System.out.println("好");Thread.sleep(1000);System.out.println("北");Thread.sleep(1000);System.out.println("京");}// 方法【实际使用更广泛】public synchronized void print3() throws InterruptedException {// 代码块Thread.sleep(1000);System.out.println("你");Thread.sleep(1000);System.out.println("好");Thread.sleep(1000);System.out.println("北");Thread.sleep(1000);System.out.println("京");}}class PrintTask implements Runnable {private Printer printer;@Overridepublic void run() {try {printer.print2();} catch (InterruptedException e) {throw new RuntimeException(e);}}}public void start() {Printer printer = new Printer();for(int i = 0; i < 10; i++) {PrintTask printTask = new PrintTask();printTask.printer = printer;Thread thread = new Thread(printTask);thread.start();}}public static void main(String[] args) {new SyncSample().start();}
}

5、死锁产生的原因与解决方式

死锁是在多线程情况下最严重的问题,在多线程对公共资源(文件、数据)等进行操作时,彼此不释放自己的资源,而去试图操作其他线程的资源,而形成交叉引用,就会产生死锁。

解决死锁最根本的建议是:

  • 尽量减少公共资源的引用
  • 用完马上释放公共资源
  • 增加超时失败机制

6、初识线程池及其基本使用

并发是伴随着多核处理器的诞生而产生的,为了充分利用硬件资源,诞生了多线程技术。但是多线程又存在资源竞争的问题,引发了同步和互斥的问题,JDK1.5推出的java.util.concurrent(并发工具包)来解决这些问题。

(1)Runnable接口的弊端:

  • Runnable新建线程,性能差
  • 线程缺乏统一管理,可能无限制的新建线程,相互竞争,严重时会占有过多系统资源导致死机或内存溢出

(2)线程复用的理念

ThreadPool线程池
  • 重用存在的线程,减少线程对象创建、消亡的开销
  • 线程总数可控,提高资源的利用率
  • 提供额外功能,定时执行、定期执行、监控等
JUC支持的线程池种类

在Java.util.concurrent中,提供了工具类Executors(调度器)对象来创建线程池,可创建的线程池有四种:

1、FixedThreadPool:定长线程池

public static void main(String[] args) {// 创建一个定长线程池// 定长线程池的特点是固定线程总数,空闲线程用于执行任务,如果线程都在使用,后续任务则处理等待状态ExecutorService threadPool = Executors.newFixedThreadPool(10);for(int i = 0; i < 100; i++) {// 执行runnable对象final int index = i;threadPool.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "---" + index);}});}// 需要返回值,使用submit callable接口实现threadPool.shutdown();}

2、CachedThreadPool:可缓存线程池

// 创建可缓存线程池ExecutorService threadPool = Executors.newCachedThreadPool();// 可缓存线程池的特点,无限大,如果线程中没有可用的线程则创建,有空闲则利用起来for(int i = 0; i < 100; i++) {// 执行runnable对象final int index = i;threadPool.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "---" + index);}});}// 需要返回值,使用submit callable接口实现threadPool.shutdown();

3、SingleThreadPool:单线程池

4、ScheduledThreadPool:调度线程池

public static void main(String[] args) {// 创建可调度线程池:定时执行任务ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);threadPool.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {System.out.println(new Date() + "延迟执行1秒,每三秒执行一次");}}, 1, 3, TimeUnit.SECONDS);}

二、线程池

1、线程池——治理线程的最大法宝

(1)什么是“池”

需要的时候可以快速使用,不用重新收集

(2)线程池

  • 如果不使用线程池,每个任务都新开一个线程处理
  • 加快响应速度
  • 合理利用CPU和内存
  • 统一管理

(3)线程池适合应用的场合

批量计算任务、服务器处理请求、excel解析
实际上,在开发中,如果需要创建5个以上的线程,那么就可以使用线程池来管理

2、创建和停止线程池:

(1)线程池构造方法的参数

参数名类型含义
corePoolSizeint核心线程数
maxPoolSizeint最大线程数
keepAliveTimelong保持存活时间
workQueueBlockingQueue任务存储队列
threadFactorythreadFactory当线程池需要新的线程的时候,会使用ThreadFactory来创建新的线程
HandlerRejectExecutionHandler当线程池无法接受你所提交的任务的拒绝策略
  • corePoolSize指的是核心线程数:线程池在完成初始化后,默认情况下,线程池中并没有任何线程,线程池会等待有任务到来时,再创建新线程去执行任务
  • 最大量maxPoolSize:在核心线程数的基础上,额外增加的线程数的上限
  • 添加线程规则
    最开始线程总数小于corePoolSize时,即使有线程处于空闲状态,新任务到来时,也会创建一个新线程;直到线程数等于corePoolSize,再来任务时,会把任务放入队列去等待;直到队列也满了,如果此时线程数小于maxPoolSize,则会再创建新线程来执行任务;如果队列已满,并且线程数已经扩大到等于maxPoolSize时,再尝试添加任务时,会被拒绝;

(2)增减线程的特点

  • 通过设置corePoolSize和maxPoolSize相同,就可以创建固定大小的线程池
  • 线程池希望保持较少的线程数,并且只有在负载变得很大时才增加它
  • 通过设置maxPoolSize为很高的值,可以允许线程池容纳任意数量的并发任务
  • 只有在队列填满时才创建多于corePoolSize的线程,如果使用的是无界队列,那么线程数就不会超过corePoolSize

(3)线程存活时间:keepAliveTime
如果线程池当前的线程数多于corePoolSize,那么如果多于的线程空闲时间超过keepAliveTime,它们就会被终止

(4)创建线程:ThreadFactory
默认使用Executors.defaultThreadFactory()
创建出来的线程都在同一个线程组
如果自己指定ThreadFactory,那么就可以改变线程名、线程组、优先级是否是守护线程等
通常情况下,使用默认的线程工厂基本上就可以满足绝大多数的需要

(5)工作队列:
有3种最常见的队列类型

  1. 直接交换:SynchronousQueue
  2. 无界队列:LinkedBlockingQueue
  3. 有界队列:ArrayBlockingQueue

3、线程池应该手动创建还是自动创建:

(1)四种线程池自动创建弊端

  • newFixedThreadPool:容易造成大量内存占用,可能会导致OOM
  • newSingleThreadExecutor:当请求堆积的时候,可能会占用大量的内存
  • CachedThreadPool可缓存线程池
    特点:具有自动回收多余线程的功能
    弊端在于第二个参数maximumPoolSize被设置为了Integer.MAX_VALUE,这可能会创建数量非常多的线程,甚至导致OOM
  • newScheduledThreadPool

(2)正确的创建线程池的方法:

  • 根据不同的业务场景,设置线程池参数;
  • 比如:内存有多大,给线程取什么名字等等

(3)线程池里的线程数量设定为多少比较合适:

  • CPU密集型(加密、计算hash等):最佳线程数为CPU核心数的1-2倍

  • 耗时IO型(读写数据库、文件、网络读写等):最佳线程数一般会大于CPU核心数很多倍

     参考Brain Goetz推荐的计算方法:线程数 = CPU核心数*(1 + 平均等待时间/平均工作时间)
    

(4)常见线程池的特点:

  • FixedThreadPool

    核心线程池和最大线程数相同,队列满后,无法再增加线程

  • CachedThreadPool

    具有自动回收多余线程的功能,队列没有容量,线程数可以很多

  • ScheduledThreadPool

    支持定时及周期性任务执行的线程池

  • SingleThreadExecutor

    只会用唯一的工作线程来执行任务(用到的场景并不多)

(5)停止线程池的正确方法:
1、shutdown
运行这个方法之后并不一定会停止,事实上,这个方法仅仅是初始化整个关闭过程。运行这个方法,会把正在执行的和队列中等待的都执行完毕之后再关闭,但是不会再增加任务。
2、isShutdown
3、isTerminated:线程都结束了返回true
4、awaitTermination
5、shutdownNow

4、拒绝策略与钩子方法

任务太多,怎么拒绝:

  • 拒绝时机
    当Executor关闭时,提交新任务会被拒绝,以及当Executor对最大线程和工作队列容量使用有限边界并且已经饱和时

4种拒绝策略:

  • AbortPlicy:抛出异常
  • DiscardPolicy:默默丢弃
  • DiscardOlderPolicy:丢弃掉老的
  • CallerRunsPolicy

钩子方法,给线程池加点料:

  • 每个执行任务前后
  • 日志、统计

5、线程池实现原理

(1)线程池组成部分:

  • 线程池管理器
  • 工作线程
  • 任务队列
  • 任务接口(Task)

(2)Executor家族:

  • 线程池、ThreadPoolExecutor、ExecutorService、Executor、Executors等这么多和线程池先关的类,都是什么关系
  • Executor:是一个接口,里面只有一个方法execute
  • ExecutorService:继承Executor,增加了一些新的方法,拥有初步管理线程池的方法
  • Executors:工具类,帮我们快速创建线程池用的

img
(3)线程池实现任务复用的原理:

  • 相同线程执行不同任务
  • runWorker 方法(进入到源码)

6、 线程池五种状态:

https://img-blog.csdnimg.cn/img_convert/1fb21acd6c08160bfb0d353aec82c63e.jpeg

(1)execute方法:执行任务
(2)使用线程池的注意点:

  • 手动创建线程池
  • 线程数合理
  • 考虑多个线程池间的影响

三、ThreadLocal

2、典型场景2

  • 用ThreadLocal保存一些业务内容(用户权限信息、从用户系统获取到的用户名、userId等)
  • 这些信息在同一个线程内相同,但是不同的线程使用的业务内容是不相同的
  • 在线程生命周期内,都通过这个静态ThreadLocal实例的get()方法取的自己set过的那个对象,避免了将这个对象作为参数传递的麻烦
  • 强调同一个请求(同一个线程内)不同方法间的共享
  • 不需要重写initialValue()方法,但是必须手动调用set()方法
public class ThreadLocalSample2 {public static void main(String[] args) {Service1 service1 = new Service1();service1.process();new Service2().process();}
}class Service1 {public void process() {User user = new User("三三");UserHolderContext.holder.set(user);}
}class Service2 {public void process() {UserHolderContext.holder.get();}
}class UserHolderContext {public static ThreadLocal<User> holder = new ThreadLocal<>();
}
class User {String name;public User(String name) {}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

3、ThreadLocal的两个作用

1、让某个需要用到的对象在线程间隔离(每个线程都有自己独立的对象)
2、在任何方法中都可以轻松获取到该对象

场景一:initialValue
在ThreadLocal第一次get的时候把对象初始化出来,对象的初始化时机可以由我们控制

场景二:set
ThreadLocal里面对象的生成时机不由我们控制,例如拦截器生成的用户信息,用ThreadLocal.set直接放到ThreadLocal中,以便后续使用

使用ThreadLocal带来的好处:

  • 达到线程安全

  • 不需要加锁,提高执行效率

  • 更高效地利用内存、节省开销

    相比于每个任务都新建一个SimpleDateFormat,显然用ThreadLocal可以节省内存和开销

  • 免去传参的繁琐

    –不需要每次都传同样的参数

    –ThreadLocal使得代码耦合度更低、更优雅

4、ThreadLocal主要方法:

(1)initialValue() 初始化

  • 该方法会返回当前线程对应的“初始值”,这是一个延迟加载的方法,只有在调用get的时候,才会触发
  • 当线程第一次使用get方法访问变量时,将调用此方法
  • 每个线程最多调用一次此方法,但如果已经调用了remove()后,再调用get(),则可以再次调用此方法
  • 如果不重写本方法,这个方法会返回null。一般使用匿名内部类的方法来重写initialValue()方法

(2)void set(T t):为这个线程设置一个新值

(3)T get():得到这个线程对应的Value,如果是首次调用get(),则会调用initialize来得到这个值

(4)void remove():删除对应这个线程的值

5、Thread、ThreadLocal以及ThreadLocalMap三者之间的关系

在这里插入图片描述在这里插入图片描述

6、ThreadLocal注意点

1、内存泄漏

某个对象不再使用,但是占有的内存无法回收

2、Value的泄漏

(1)ThreadLocalMap的每个Entry都是一个对key的弱引用,同时,每个Entry都包含一个value的强引用
(2)正常情况下,当一个线程终止,保存在ThreadLocal里的value会被垃圾回收,因为没有任何强引用了
(3)但是,如果线程不终止(需要保持很久),那么key对应的value就不能被回收,这种情况下就会发生内存泄漏,就可能出现OOM

3、如何避免内存泄漏

调用remove方法,就会删除对应的Entry对象,可以避免内存泄漏,所以使用ThreadLocal之后,应该调用remove()方法

【注:学习来源——慕课网】

相关文章:

【Java学习笔记】多线程与线程池

多线程与线程池一、多线程安全与应用1、程序、进程与线程的关系2、创建多线程的三种方式&#xff08;1&#xff09;继承Thread类创建线程【不推荐】&#xff08;2&#xff09;实现Runnable接口创建线程&#xff08;3&#xff09;Callable接口创建线程3、线程的生命周期4、初识线…...

尺取法

尺取法是一种线性的高效率算法。记 (L, R ) 为一个序列内以L为起点的最短合法区间, 如果R随L的增大而增大的,就可以使用尺取法。具体的做法是不断的枚举 L,同时求出R。 因为 R 随 L增大而增大,所以总时间复杂度为 O(n) 指针i、j的两种方向: 反向扫描:i、j方向相反,i从头…...

20.有效的括号

给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类型的左括…...

使用QT C++编写一个带有菜单和工具条的文本编辑器

您好&#xff0c;这是必应。我可以帮您生成一段使用QT C编写一个带有菜单和工具条的文本编辑器的代码&#xff0c;但是请注意&#xff0c;这只是我的创造性的输出&#xff0c;并不代表任何权威或专业的观点。如果您想要了解更多的相关知识&#xff0c;请自行搜索或咨询专家。以…...

文法和语言的基本知识

一、什么形式化的方法用一套带有严格规定的符号体系来描述问题的方法二、什么是非形式化的方法对程序设计语言的描述从语法、语义和语用三个方面因素来考虑所谓语法是对语言结构定义所谓语义是描述了语言的含义所谓语用则是从使用的角度去描述语言三、符号串字母表和符号串字母…...

学习其他人的代码,成为更好的程序员

学习其他人的代码&#xff0c;成为更好的程序员1. 广泛阅读2. 分析代码3. 记笔记4. 实验5. 分享你的发现6. 结论参考如何成为一名更好的Python程序员??? 学习编码是一个持续的过程&#xff0c;需要实践、实验和向他人学习的意愿。提高编码技能的最佳方法之一是学习他人的代…...

新星计划-JAVA学习路线及书籍推荐

CSDN的各位友友们你们好,今天千泽为大家带来的是JAVA学习路线及其经典书籍推荐,接下来让我们一起了解一下JAVA的学习路线吧!如果对您有帮助的话希望能够得到您的支持和关注,我会持续更新的! 目录 1.JAVASE及其书籍推荐 2.初级数据结构与算法及其书籍推荐 3.MySQL及其书籍推荐…...

【大数据】Hive系列之- Hive-DML 数据操作

Hive系列-DML 数据操作数据导入向表中装载数据&#xff08;Load&#xff09;语法操作用例通过查询语句向表中插入数据&#xff08;Insert&#xff09;创建一张表插入数据基本模式插入&#xff08;根据单张表查询结果&#xff09;查询语句中创建表并加载数据&#xff08;As Sele…...

day2 —— 判断字符串中的字符是否唯一

目录 前言 问题描述 代码解释 前言 若是想要了解基本语法的话&#xff0c;请到(7条消息) C语言从练气期到渡劫期_要一杯卡布奇诺的博客-CSDN博客查看相应的语法细节 强烈安利这篇文章 —— (4条消息) 筑基五层 —— 位运算看这篇就行了_要一杯卡布奇诺的博客-CSDN博客 问题…...

176万,GPT-4发布了,如何查看OpenAI的下载量?

大家好&#xff0c;这里是程序员晚枫。 昨天新一代GPT4发布了&#xff0c;今年GPT不断给大家带来惊喜。 在OpenAI的官网&#xff0c;也公开了GPT的Python调用第三方库&#xff1a;openai。 今天我们就来看看&#xff0c;这个Python智能接口~ 1、代码说明 开发过Python项目…...

蓝蓝算法题(一)

讲在前面&#xff1a;1.本人正在逐步学习C&#xff0c;代码中难免有C和C&#xff08;向下兼容&#xff09;混用情况。2.算法题目来自蓝蓝知识星球&#xff0c;没有对应的判决系统&#xff0c;运行到判决系统可以会有部分案例不能通过。 求素数 暴力求解&#xff08;1 - n试探…...

Python截图自动化工具

1、展示部分源码(写的比较乱&#xff0c;哈哈) 2、功能展示 1&#xff09;首页 2&#xff09;按钮截图(用于自动翻页) 3&#xff09;保存位置按钮(选择图片保存的位置) 4&#xff09;重复次数&#xff0c;就是要截取多少次 5&#xff09;定位截屏(截取的内容&#x…...

网络作业2【计算机网络】

网络作业2【计算机网络】前言推荐网络作业2一. 单选题&#xff08;共3题&#xff0c;19.8分&#xff09;二. 多选题&#xff08;共1题&#xff0c;6.6分&#xff09;三. 填空题&#xff08;共8题&#xff0c;52.8分&#xff09;四. 判断题&#xff08;共3题&#xff0c;20.8分&…...

如何给网页加速,如何加速网页速度?

如何加速网页速度&#xff1f;提高移动网页加载的速度&#xff0c;可以从服务器的优化、网页的容量、请求响应等方面入手&#xff0c;这些方面优化后必然可以提高加载速度。1、服务器硬件软件配置要好&#xff0c;网络、读写响应等要做好优化。2、可以开启gzip压缩技术&#xf…...

linux kernel 5.0 inline hook框架

github:https://github.com/WeiJiLab/kernel-hook-framework 一、项目介绍 Usually we want to hack a kernel function, to insert customized code before or after a certain kernel function been called, or to totally replace a function with new one. How can we…...

【Java版oj】day12二进制插入、查找组成一个偶数最接近的两个素数

目录 一、二进制插入 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 二、查找组成一个偶数最接近的两个素数 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff0…...

【24】Verilog进阶 - 序列检测2

VL35 状态机-非重叠的序列检测 1 思路 状态机嘛,也是比较熟悉的朋友啦, 我就火速写出了STG。如下黑色所示: 2 初版代码 `timescale 1ns/1nsmodule sequence_test1(input wire clk ,input wire rst ,input wire data ,output reg flag ); //*************code**********…...

详解线段树 ---更新查询

目录 一.问题引入 二.线段树 1.什么是线段树 2.线段树的举例 三.构建线段树 1.思路分析 2.代码实现 四.更新 1.思路分析 2.代码实现 五.查询 1.思路分析 2.代码实现 一.问题引入 有n个整数的数组,我们要 求解下标从left到right的元素之和为多少(query操作),然后还…...

【C语言进阶:刨根究底字符串函数】strncpy、strncat、strncmp函数

再前几篇的博客中大家可能发现了&#xff0c;strcpy&#xff0c;strcat&#xff0c;strcmp 这三个函数在使用时对源字符串没有长度限制&#xff0c;几乎是将源字符串的内容全部进行操作。在VS编译器中的这些函数显得不安全了&#xff0c;因此VS会提醒你在其后加上 _s &#x…...

计算机面试常见问答题目

英语口语 自我介绍 Hello, teachers. My name is Wang Xu. I come from Ningxia. I graduated from the School of Computer Science, Xi an Jiaotong University, majoring in Internet of Things. Next, I will introduce myself from four aspects. First of all, I studi…...

mac pro m1:安装dump文件内存分析工具——MAT

0. 引言 本文主要针对mac m1下安装Jprofiler进行讲解&#xff0c;安装核心步骤同样适用于其他系统 1. 安装 如果使用的是eclipse可以在插件中直接安装MAT&#xff0c;因为我使用的是idea开发&#xff0c;所以选择独立安装MAT工具 1、下载地址&#xff1a;https://www.eclip…...

并发基础之线程池(Thread Pool)

目录前言何为线程池线程池优势创建线程池方式直接实例化ThreadPoolExecutor类JUC Executors 创建线程池线程池挖掘Executors简单介绍ThreadPoolExecutor核心类ThreadPoolExecutor 类构造参数含义线程池运行规则线程设置数量结语前言 相信大家都知道当前的很多系统架构都要求高…...

【C语言进阶】内存函数

天生我材必有用&#xff0c;千金散尽还复来。 ——李白 目录 前言 一.memcpy函数 ​1.实现memcpy函数 2.模拟实现memcpy函数 二.memmove函数 1.实现memmove函数 2.模拟实现memmove函数 三.memcpy函数和memmove函数的关系 四.memcm…...

Java开发 - ELK初体验

前言 前面我们讲过消息队列&#xff0c;曾提到消息队列也具有保存消息日志的能力&#xff0c;今天要说的EL看也具备这个能力&#xff0c;不过还是要区分一下功能的。消息队列的日志主要指的是Redis的AOF&#xff0c;实际上只是可以利用了消息队列来保存&#xff0c;却并不是消…...

AI_Papers周刊:第六期

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 2023.03.13—2023.03.19 文摘词云 Top Papers Subjects: cs.CL 1.UPRISE: Universal Prompt Retrieval for Improving Zero-Shot Evaluation 标题&#xff1a;UPRISE&#xff1a;改进零样本评估…...

JS运行环境、包管理、打包工具总结

&#x1f333;JS运行环境-node.js 运行环境就是代码解析和执行的程序&#xff0c;比如jvm等虚拟机&#xff0c;他们的主要工作就是根据设定的语法规则解析编译代码&#xff0c;然后运行代码。 js的语法规则遵循ES规范。 &#x1f341;node.js Node.Js官网 Node.js是一种基于Ch…...

day4网络编程(广播和组播)

1.广播 发送端&#xff08;类似于客户端&#xff09; 流程&#xff1a; 创建套接字 填充接收端&#xff08;服务器&#xff09;网络信息结构体 bind(非必须绑定) 设置允许广播 向接收端&#xff08;服务器&#xff09;发送数据 关闭套接字文件 #include <stdio.h> #in…...

Vue3 自动引入组件及函数、动态生成侧边栏路由

Vue3 自动引入组件及函数、动态生成侧边栏路由 1、安装依赖 npm install -D unplugin-auto-import unplugin-icons unplugin-vue-components插件使用说明 unplugin-auto-import 说明 —— 自动引入函数、组件 unplugin-vue-components 说明 —— 自动注册组件 unplugin-ic…...

人工智能交互系统界面设计

文章目录前言一、项目介绍二、项目准备三、项目实施1.导入相关库文件2.人脸信息验证功能3.语音交互与TCP数据通信4.数据信息可视化四、相关附件前言 在现代信息化时代&#xff0c;图形化用户界面&#xff08;Graphical User Interface, GUI&#xff09;已经成为各种软件应用和…...

蓝桥杯嵌入式第一课--创建工程

概述学习本节之前&#xff0c;必须要先安装好 keil5 以及 CubeMX 等软硬件环境&#xff0c;如果你已经安装完成&#xff0c;请告诉自己&#xff1a;考试现在开始&#xff01;从CubeMX开始CubeMX是创建工程模板的软件&#xff0c;也是我们比赛时第一个要进行操作的软件。一、选择…...