Java基础常见面试题总结-并发(一)

线程池

线程池:一个管理线程的池子。

为什么平时都是使用线程池创建线程,直接new一个线程不好吗?

嗯,手动创建线程有两个缺点

  1. 不受控风险
  2. 频繁创建开销大

为什么不受控

系统资源有限,每个人针对不同业务都可以手动创建线程,并且创建线程没有统一标准,比如创建的线程有没有名字等。当系统运行起来,所有线程都在抢占资源,毫无规则,混乱场面可想而知,不好管控。

频繁手动创建线程为什么开销会大?跟new Object() 有什么差别?

虽然Java中万物皆对象,但是new Thread() 创建一个线程和 new Object()还是有区别的。

new Object()过程如下:

  1. JVM分配一块内存 M
  2. 在内存 M 上初始化该对象
  3. 将内存 M 的地址赋值给引用变量 obj

创建线程的过程如下:

  1. JVM为一个线程栈分配内存,该栈为每个线程方法调用保存一个栈帧
  2. 每一栈帧由一个局部变量数组、返回值、操作数堆栈和常量池组成
  3. 每个线程获得一个程序计数器,用于记录当前虚拟机正在执行的线程指令地址
  4. 系统创建一个与Java线程对应的本机线程
  5. 将与线程相关的描述符添加到JVM内部数据结构中
  6. 线程共享堆和方法区域

创建一个线程大概需要1M左右的空间(Java8,机器规格2c8G)。可见,频繁手动创建/销毁线程的代价是非常大的。

为什么使用线程池?

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性。统一管理线程,避免系统创建大量同类线程而导致消耗完内存。

线程池执行原理?

线程池执行流程

  1. 当线程池里存活的线程数小于核心线程数corePoolSize时,这时对于一个新提交的任务,线程池会创建一个线程去处理任务。当线程池里面存活的线程数小于等于核心线程数corePoolSize时,线程池里面的线程会一直存活着,就算空闲时间超过了keepAliveTime,线程也不会被销毁,而是一直阻塞在那里一直等待任务队列的任务来执行。
  2. 当线程池里面存活的线程数已经等于corePoolSize了,这是对于一个新提交的任务,会被放进任务队列workQueue排队等待执行。
  3. 当线程池里面存活的线程数已经等于corePoolSize了,并且任务队列也满了,假设maximumPoolSize>corePoolSize,这时如果再来新的任务,线程池就会继续创建新的线程来处理新的任务,知道线程数达到maximumPoolSize,就不会再创建了。
  4. 如果当前的线程数达到了maximumPoolSize,并且任务队列也满了,如果还有新的任务过来,那就直接采用拒绝策略进行处理。默认的拒绝策略是抛出一个RejectedExecutionException异常。

线程池参数有哪些?

ThreadPoolExecutor 的通用构造函数:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler);

1、corePoolSize:当有新任务时,如果线程池中线程数没有达到线程池的基本大小,则会创建新的线程执行任务,否则将任务放入阻塞队列。当线程池中存活的线程数总是大于 corePoolSize 时,应该考虑调大 corePoolSize。

2、maximumPoolSize:当阻塞队列填满时,如果线程池中线程数没有超过最大线程数,则会创建新的线程运行任务。否则根据拒绝策略处理新任务。非核心线程类似于临时借来的资源,这些线程在空闲时间超过 keepAliveTime 之后,就应该退出,避免资源浪费。

3、BlockingQueue:存储等待运行的任务。

4、keepAliveTime非核心线程空闲后,保持存活的时间,此参数只对非核心线程有效。设置为0,表示多余的空闲线程会被立即终止。

5、TimeUnit:时间单位

TimeUnit.DAYS
TimeUnit.HOURS
TimeUnit.MINUTES
TimeUnit.SECONDS
TimeUnit.MILLISECONDS
TimeUnit.MICROSECONDS
TimeUnit.NANOSECONDS

6、ThreadFactory:每当线程池创建一个新的线程时,都是通过线程工厂方法来完成的。在 ThreadFactory 中只定义了一个方法 newThread,每当线程池需要创建新线程就会调用它。

public class MyThreadFactory implements ThreadFactory {
    private final String poolName;
    
    public MyThreadFactory(String poolName) {
        this.poolName = poolName;
    }
    
    public Thread newThread(Runnable runnable) {
        return new MyAppThread(runnable, poolName);//将线程池名字传递给构造函数,用于区分不同线程池的线程
    }
}

7、RejectedExecutionHandler:当队列和线程池都满了的时候,根据拒绝策略处理新任务。

AbortPolicy:默认的策略,直接抛出RejectedExecutionException
DiscardPolicy:不处理,直接丢弃
DiscardOldestPolicy:将等待队列队首的任务丢弃,并执行当前任务
CallerRunsPolicy:由调用线程处理该任务

线程池大小怎么设置?

如果线程池线程数量太小,当有大量请求需要处理,系统响应比较慢,会影响用户体验,甚至会出现任务队列大量堆积任务导致OOM。

如果线程池线程数量过大,大量线程可能会同时抢占 CPU 资源,这样会导致大量的上下文切换,从而增加线程的执行时间,影响了执行效率。

CPU 密集型任务(N+1): 这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N(CPU 核心数)+1,多出来的一个线程是为了防止某些原因导致的线程阻塞(如IO操作,线程sleep,等待锁)而带来的影响。一旦某个线程被阻塞,释放了CPU资源,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。

I/O 密集型任务(2N): 系统的大部分时间都在处理 IO 操作,此时线程可能会被阻塞,释放CPU资源,这时就可以将 CPU 交出给其它线程使用。因此在 IO 密集型任务的应用中,可以多配置一些线程,具体的计算方法:最佳线程数 = CPU核心数 * (1/CPU利用率) = CPU核心数 * (1 + (IO耗时/CPU耗时)),一般可设置为2N。

线程池的类型有哪些?适用场景?

常见的线程池有 FixedThreadPoolSingleThreadExecutorCachedThreadPoolScheduledThreadPool。这几个都是 ExecutorService 线程池实例。

FixedThreadPool

固定线程数的线程池。任何时间点,最多只有 nThreads 个线程处于活动状态执行任务。

public static ExecutorService newFixedThreadPool(int nThreads) {
	return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}

使用无界队列 LinkedBlockingQueue(队列容量为 Integer.MAX_VALUE),运行中的线程池不会拒绝任务,即不会调用RejectedExecutionHandler.rejectedExecution()方法。

maxThreadPoolSize 是无效参数,故将它的值设置为与 coreThreadPoolSize 一致。

keepAliveTime 也是无效参数,设置为0L,因为此线程池里所有线程都是核心线程,核心线程不会被回收(除非设置了executor.allowCoreThreadTimeOut(true))。

适用场景:适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。需要注意的是,FixedThreadPool 不会拒绝任务,在任务比较多的时候会导致 OOM。

SingleThreadExecutor

只有一个线程的线程池。

public static ExecutionService newSingleThreadExecutor() {
	return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}

使用无界队列 LinkedBlockingQueue。线程池只有一个运行的线程,新来的任务放入工作队列,线程处理完任务就循环从队列里获取任务执行。保证顺序的执行各个任务。

适用场景:适用于串行执行任务的场景,一个任务一个任务地执行。在任务比较多的时候也是会导致 OOM。

CachedThreadPool

根据需要创建新线程的线程池。

public static ExecutorService newCachedThreadPool() {
	return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
}

如果主线程提交任务的速度高于线程处理任务的速度时,CachedThreadPool 会不断创建新的线程。极端情况下,这样会导致耗尽 cpu 和内存资源。

使用没有容量的SynchronousQueue作为线程池工作队列,当线程池有空闲线程时,SynchronousQueue.offer(Runnable task)提交的任务会被空闲线程处理,否则会创建新的线程处理任务。

适用场景:用于并发执行大量短期的小任务。CachedThreadPool允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致 OOM。

ScheduledThreadPoolExecutor

在给定的延迟后运行任务,或者定期执行任务。在实际项目中基本不会被用到,因为有其他方案选择比如quartz

使用的任务队列 DelayQueue 封装了一个 PriorityQueuePriorityQueue 会对队列中的任务进行排序,时间早的任务先被执行(即ScheduledFutureTasktime 变量小的先执行),如果time相同则先提交的任务会被先执行(ScheduledFutureTasksquenceNumber 变量小的先执行)。

执行周期任务步骤:

  1. 线程从 DelayQueue 中获取已到期的 ScheduledFutureTask(DelayQueue.take())。到期任务是指 ScheduledFutureTask的 time 大于等于当前系统的时间;
  2. 执行这个 ScheduledFutureTask
  3. 修改 ScheduledFutureTask 的 time 变量为下次将要被执行的时间;
  4. 把这个修改 time 之后的 ScheduledFutureTask 放回 DelayQueue 中(DelayQueue.add())。

img

适用场景:周期性执行任务的场景,需要限制线程数量的场景。

怎么判断线程池的任务是不是执行完了?

有几种方法:

1、使用线程池的原生函数isTerminated();

executor提供一个原生函数isTerminated()来判断线程池中的任务是否全部完成。如果全部完成返回true,否则返回false。

2、使用重入锁,维持一个公共计数

所有的普通任务维持一个计数器,当任务完成时计数器加一(这里要加锁),当计数器的值等于任务数时,这时所有的任务已经执行完毕了。

3、使用CountDownLatch

它的原理跟第二种方法类似,给CountDownLatch一个计数值,任务执行完毕后,调用countDown()执行计数值减一。最后执行的任务在调用方法的开始调用await()方法,这样整个任务会阻塞,直到这个计数值为零,才会继续执行。

这种方式的缺点就是需要提前知道任务的数量。

4、submit向线程池提交任务,使用Future判断任务执行状态

使用submit向线程池提交任务与execute提交不同,submit会有Future类型的返回值。通过future.isDone()方法可以知道任务是否执行完成。

为什么要使用Executor线程池框架呢?

  • 每次执行任务都通过new Thread()去创建线程,比较消耗性能,创建一个线程是比较耗时、耗资源的
  • 调用new Thread()创建的线程缺乏管理,可以无限制的创建,线程之间的相互竞争会导致过多占用系统资源而导致系统瘫痪
  • 直接使用new Thread()启动的线程不利于扩展,比如定时执行、定期执行、定时定期执行、线程中断等都不好实现

execute和submit的区别

execute只能提交Runnable类型的任务,无返回值。submit既可以提交Runnable类型的任务,也可以提交Callable类型的任务,会有一个类型为Future的返回值,但当任务类型为Runnable时,返回值为null。

execute在执行任务时,如果遇到异常会直接抛出,而submit不会直接抛出,只有在使用Future的get方法获取返回值时,才会抛出异常

execute所属顶层接口是Executor,submit所属顶层接口是ExecutorService,实现类ThreadPoolExecutor重写了execute方法,抽象类AbstractExecutorService重写了submit方法。

进程线程

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间。

线程是比进程更小的执行单位,它是在一个进程中独立的控制流,一个进程可以启动多个线程,每条线程并行执行不同的任务。

线程的生命周期

初始(NEW):线程被构建,还没有调用 start()。

运行(RUNNABLE):包括操作系统的就绪和运行两种状态。

阻塞(BLOCKED):一般是被动的,在抢占资源中得不到资源,被动的挂起在内存,等待资源释放将其唤醒。线程被阻塞会释放CPU,不释放内存。

等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。

超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。

终止(TERMINATED):表示该线程已经执行完毕。

img

图片来源:Java并发编程的艺术

讲讲线程中断?

线程中断即线程运行过程中被其他线程给打断了,它与 stop 最大的区别是:stop 是由系统强制终止线程,而线程中断则是给目标线程发送一个中断信号,如果目标线程没有接收线程中断的信号并结束线程,线程则不会终止,具体是否退出或者执行其他逻辑取决于目标线程。

线程中断三个重要的方法:

1、java.lang.Thread#interrupt

调用目标线程的interrupt()方法,给目标线程发一个中断信号,线程被打上中断标记。

2、java.lang.Thread#isInterrupted()

判断目标线程是否被中断,不会清除中断标记。

3、java.lang.Thread#interrupted

判断目标线程是否被中断,会清除中断标记。

private static void test2() {
    Thread thread = new Thread(() -> {
        while (true) {
            Thread.yield();

            // 响应中断
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("Java技术栈线程被中断,程序退出。");
                return;
            }
        }
    });
    thread.start();
    thread.interrupt();
}

创建线程有哪几种方式?

  • 通过扩展Thread类来创建多线程
  • 通过实现Runnable接口来创建多线程
  • 实现Callable接口,通过FutureTask接口创建线程。
  • 使用Executor框架来创建线程池。

继承 Thread 创建线程代码如下。run()方法是由jvm创建完操作系统级线程后回调的方法,不可以手动调用,手动调用相当于调用普通方法。


public class MyThread extends Thread {
    public MyThread() {
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread() + ":" + i);
        }
    }

    public static void main(String[] args) {
        MyThread mThread1 = new MyThread();
        MyThread mThread2 = new MyThread();
        MyThread myThread3 = new MyThread();
        mThread1.start();
        mThread2.start();
        myThread3.start();
    }
}

Runnable 创建线程代码


public class RunnableTest {
    public static  void main(String[] args){
        Runnable1 r = new Runnable1();
        Thread thread = new Thread(r);
        thread.start();
        System.out.println("主线程:["+Thread.currentThread().getName()+"]");
    }
}

class Runnable1 implements Runnable{
    @Override
    public void run() {
        System.out.println("当前线程:"+Thread.currentThread().getName());
    }
}

实现Runnable接口比继承Thread类所具有的优势:

  1. 可以避免java中的单继承的限制
  2. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类

Callable 创建线程代码


public class CallableTest {
    public static void main(String[] args) {
        Callable1 c = new Callable1();

        //异步计算的结果
        FutureTask<Integer> result = new FutureTask<>(c);

        new Thread(result).start();

        try {
            //等待任务完成,返回结果
            int sum = result.get();
            System.out.println(sum);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

}

class Callable1 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;

        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
}

使用 Executor 创建线程代码

/**
 * @author: 程序员大彬
 * @time: 2021-09-11 10:44
 */
public class ExecutorsTest {
    public static void main(String[] args) {
        //获取ExecutorService实例,生产禁用,需要手动创建线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        //提交任务
        executorService.submit(new RunnableDemo());
    }
}

class RunnableDemo implements Runnable {
    @Override
    public void run() {
        System.out.println("大彬");
    }
}

什么是线程死锁?

线程死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象。若无外力作用,它们都将无法推进下去。

如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方持有的资源,所以这两个线程就会互相等待而进入死锁状态。

死锁

下面通过例子说明线程死锁,代码来自并发编程之美。

public class DeadLockDemo {
    private static Object resource1 = new Object();//资源 1
    private static Object resource2 = new Object();//资源 2

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (resource1) {
                System.out.println(Thread.currentThread() + "get resource1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource2");
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2");
                }
            }
        }, "线程 1").start();

        new Thread(() -> {
            synchronized (resource2) {
                System.out.println(Thread.currentThread() + "get resource2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource1");
                synchronized (resource1) {
                    System.out.println(Thread.currentThread() + "get resource1");
                }
            }
        }, "线程 2").start();
    }
}

代码输出如下:

Thread[线程 1,5,main]get resource1
Thread[线程 2,5,main]get resource2
Thread[线程 1,5,main]waiting get resource2
Thread[线程 2,5,main]waiting get resource1

线程 A 通过 synchronized (resource1) 获得 resource1 的监视器锁,然后通过 Thread.sleep(1000)。让线程 A 休眠 1s 为的是让线程 B 得到执行然后获取到 resource2 的监视器锁。线程 A 和线程 B 休眠结束了都开始企图请求获取对方的资源,然后这两个线程就会陷入互相等待的状态,这也就产生了死锁。

线程死锁怎么产生?怎么避免?

死锁产生的四个必要条件

  • 互斥:一个资源每次只能被一个进程使用
  • 请求与保持:一个进程因请求资源而阻塞时,不释放获得的资源
  • 不剥夺:进程已获得的资源,在未使用之前,不能强行剥夺
  • 循环等待:进程之间循环等待着资源

避免死锁的方法

  • 互斥条件不能破坏,因为加锁就是为了保证互斥
  • 一次性申请所有的资源,避免线程占有资源而且在等待其他资源
  • 占有部分资源的线程进一步申请其他资源时,如果申请不到,主动释放它占有的资源
  • 按序申请资源

线程run和start的区别?

  • 当程序调用start()方法,将会创建一个新线程去执行run()方法中的代码。run()就像一个普通方法一样,直接调用run()的话,不会创建新线程。
  • 一个线程的 start() 方法只能调用一次,多次调用会抛出 java.lang.IllegalThreadStateException 异常。run() 方法则没有限制。

线程都有哪些方法?

start

用于启动线程。

getPriority

获取线程优先级,默认是5,线程默认优先级为5,如果不手动指定,那么线程优先级具有继承性,比如线程A启动线程B,那么线程B的优先级和线程A的优先级相同

setPriority

设置线程优先级。CPU会尽量将执行资源让给优先级比较高的线程。

interrupt

告诉线程,你应该中断了,具体到底中断还是继续运行,由被通知的线程自己处理。

当对一个线程调用 interrupt() 时,有两种情况:

  1. 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。
  2. 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true。不过,被设置中断标志的线程可以继续正常运行,不受影响。

interrupt() 并不能真正的中断线程,需要被调用的线程自己进行配合才行。

join

等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

yield

暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。

sleep

使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,线程自动转为Runnable状态。

如何停止一个正在运行的线程?

  1. 使用共享变量的方式。共享变量可以被多个执行相同任务的线程用来作为是否停止的信号,通知停止线程的执行。
  2. 使用interrupt方法终止线程。当一个线程被阻塞,处于不可运行状态时,即使主程序中将该线程的共享变量设置为true,但该线程此时根本无法检查循环标志,当然也就无法立即中断。这时候可以使用Thread提供的interrupt()方法,因为该方法虽然不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

垃圾分类|城市垃圾分类管理系统|基于Springboot的城市垃圾分类管理系统设计与实现(源码+数据库+文档)

城市垃圾分类管理系统目录 目录 基于Springboot的城市垃圾分类管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、垃圾列表 2、公告信息管理 3、公告类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 …

thinkphp+vue企业产品展示网站f7enu

本文首先介绍了企业产品展示网站管理技术的发展背景与发展现状&#xff0c;然后遵循软件常规开发流程&#xff0c;首先针对系统选取适用的语言和开发平台&#xff0c;根据需求分析制定模块并设计数据库结构&#xff0c;再根据系统总体功能模块的设计绘制系统的功能模块图&#…

qml之Control类型布局讲解,padding属性和Inset属性细讲

1、Control布局图 2、如何理解&#xff1f; *padding和*Inset参数如何理解呢&#xff1f; //main.qml import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQuick.Controls 1.4 import QtQml 2.12ApplicationWindow {id: windowvisible: …

CentOS7.9+Kubernetes1.29.2+Docker25.0.3高可用集群二进制部署

CentOS7.9Kubernetes1.29.2Docker25.0.3高可用集群二进制部署 Kubernetes高可用集群&#xff08;Kubernetes1.29.2Docker25.0.3&#xff09;二进制部署二进制软件部署flannel v0.22.3网络&#xff0c;使用的etcd是版本3&#xff0c;与之前使用版本2不同。查看官方文档进行了解…

无人机导航技术,无人机导航理论基础,无人机导航技术应用发展详解

惯性/卫星定位组合是一种比较理想的组合导航系统。在无人机导航领域&#xff0c;多年来惯性/卫星定位组合导航系统的研究一直受到普遍的关注&#xff0c;大量的理论研究成果得到实际应用。 常见的几类导航系统 单一导航 卫星导航系统 、多普勒导航、惯性导航系统(INS) 、图形…

苹果展示 AI 新模型 MGIE,可一句话精修图片

苹果公司近日发布了名为“MGIE”的新型开源人工智能模型&#xff0c;它可以根据自然语言指令编辑图像。 2 月 8 日消息&#xff0c;相比较微软的风生水起&#xff0c;苹果公司在 AI 领域的布局显得低调很多&#xff0c;但这并不意味着苹果在该领域就没有丝毫建树。苹果公司近日…

Unresolved reference: kotlinx 和 Unresolved reference:xxx

Unresolved reference: kotlinx 这个报错是因为build.gradle中忘记apply plugin了 apply plugin: kotlin-android-extensions如下 同步以后再次编译发现报错 Unresolved reference:xxx 是因为用于使用 Gradle 构建的 Kotlin 版本与 IDE 插件中的版本不一样的原因 解决方法 …

Lag-Llama:第一个时间序列预测的开源基础模型介绍和性能测试

2023年10月&#xff0c;我们发表了一篇关于TimeGPT的文章&#xff0c;TimeGPT是时间序列预测的第一个基础模型之一&#xff0c;具有零样本推理、异常检测和共形预测能力。 虽然TimeGPT是一个专有模型&#xff0c;只能通过API访问。但是它还是引发了对时间序列基础模型的更多研…

算法刷题:有效三角形个数

有效三角形个数 .题目链接题目详情算法原理补充知识点双指针:对撞指针 我的答案 . 题目链接 有效三角形个数 题目详情 算法原理 补充知识点 有效三角形需要满足的条件: ab>cac>bbc>a 其实在满足1的时候,c是最大的,那么2和3是显然成立的,因此我们可以这样解题: 对…

C# winfrom中NPOI操作EXCEL

前言 1.整个Excel表格叫做工作表&#xff1a;WorkBook&#xff08;工作薄&#xff09;&#xff0c;包含的叫页&#xff08;工作表&#xff09;&#xff1a;Sheet&#xff1b;行&#xff1a;Row&#xff1b;单元格Cell。 2.忘了告诉大家npoi是做什么的了&#xff0c;npoi 能够读…

react 【七】各种hooks的使用/SPA的缺点

文章目录 1、Hook1.1 为什么会出现hook1.2 useState1.3 useEffect1.4 useContext1.5 useReducer1.6 useCallback1.7 useMemo1.8 useRef1.8.1 ref绑定dom1.8.2 ref解决闭包缺陷 1.9 useImperativeHandle1.10 useLayoutEffect1.11 自定义Hook1.11.1 什么是自定义Hook1.11.2 Conte…

Python 字符串格式化输出

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 前言 字符串格式化是编程中一个常见的需求&#xff0c;它可以们将不同类型的数据&#xff08;如数字、文本、日…

Django问题报错:TypeError: as_view() takes 1 positional argument but 2 were given

一、错误位置 from django.urls import pathfrom users_app.views import RegisterView, LoginView, LogoutViewapp_name users urlpatterns [path("register/", RegisterView.as_view, name"register"),path("login/", LoginView.as_view, n…

基于四叉树的图像分割算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ........................................................... Imgs(dx 1 : dx R1, dy 1 …

阿里云幻兽帕鲁Linux 服务器下载游戏存档的方法

阿里云幻兽帕鲁Linux 服务器下载游戏存档的方法也非常简单。 远程连接到阿里云的 linux服务器后&#xff0c;可以在 ECS 远程连接命令行界面&#xff0c;点击左上角的文件&#xff0c;打开文件树。通过一行命令打包。 在打包后的 Saved.tar 文件上右键&#xff0c;选择 下载文…

【Go语言】Go项目工程管理

GO 项目工程管理&#xff08;Go Modules&#xff09; Go 1.11 版本开始&#xff0c;官方提供了 Go Modules 进行项目管理&#xff0c;Go 1.13开始&#xff0c;Go项目默认使用 Go Modules 进行项目管理。 使用 Go Modules的好处是不再需要依赖 GOPATH&#xff0c;可以在任意位…

《剑指offer》

本专题是分享剑指offer的一些题目&#xff0c;开始刷题计划。 二维数组的中的查找【https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId13&tqId11154&ru/exam/oj】 描述 在一个二维数组array中&#xff08;每个一维数组的长度相同&#xff0…

Python4Delphi: Delphi 程序使用 Python 抓取网页

想用程序去抓取一个网页的内容&#xff0c;Delphi 有自己的 HTTP 库。比如 Indy 的 TIdHTTP&#xff0c;或者 TNetHTTPClient。 这里测试一下使用 Python 的 HTTP 库抓取网页&#xff0c;然后把抓取的内容给 Delphi 的程序。 Delphi 程序&#xff0c;界面上拖控件如下&#x…

jenkins-maven环境的安装

jenkins-maven环境的安装

Codeforces Round 924 (Div. 2) B - D

B. Equalize 题目&#xff1a; 思路&#xff1a;首先排序然后去重&#xff08;可以用set来去重&#xff09;&#xff0c;我们可以肯定的是&#xff0c;如果连续k个数最大值最小值的差小于等于n的话&#xff0c;那么这个长度为k的区间就符合答案要求&#xff0c;那么k就和答案…
最新文章