Java 线程池:深入理解与高效应用

在 Java 并发编程中,线程池是一种非常重要的技术。它可以有效地管理和复用线程,提高系统的性能和资源利用率。本文将深入探讨 Java 线程池的概念、原理、使用方法以及最佳实践,帮助读者更好地理解和应用线程池。

一、引言

在现代软件开发中,多线程编程是提高程序性能和响应性的重要手段。然而,直接创建和管理线程会带来一些问题,如线程创建和销毁的开销、资源浪费、线程过多导致的系统性能下降等。为了解决这些问题,Java 提供了线程池技术。线程池可以预先创建一定数量的线程,当有任务需要执行时,从线程池中获取一个空闲线程来执行任务,任务完成后,线程不会被立即销毁,而是返回线程池等待下一个任务。这样可以避免频繁地创建和销毁线程,提高系统的性能和资源利用率。

二、线程池的概念与原理

(一)线程池的基本概念

线程池是一种管理线程的工具,它包含了一组预先创建的线程和一个任务队列。当有任务需要执行时,将任务提交到任务队列中,线程池中的线程会从任务队列中获取任务并执行。如果任务队列中没有任务,线程会进入等待状态,直到有新的任务到来。当线程执行完一个任务后,它会继续从任务队列中获取下一个任务,或者进入等待状态,等待新的任务到来。

(二)线程池的工作原理

  1. 线程池的创建
    • 在创建线程池时,可以指定线程池的核心线程数量、最大线程数量、任务队列的类型和大小等参数。核心线程数量是指线程池中始终保持运行的线程数量,即使这些线程处于空闲状态。最大线程数量是指线程池中允许的最大线程数量,当任务队列已满且核心线程都在忙碌时,线程池会创建新的线程来执行任务,直到线程数量达到最大线程数量。
  2. 任务的提交
    • 当有任务需要执行时,可以通过线程池的execute方法或submit方法将任务提交到线程池中。execute方法用于提交一个Runnable任务,没有返回值;submit方法用于提交一个Callable任务,有返回值。提交任务后,线程池会根据当前的线程状态和任务队列的情况来决定如何执行任务。
  3. 线程的执行
    • 线程池中的线程会从任务队列中获取任务并执行。如果任务队列中没有任务,线程会进入等待状态,直到有新的任务到来。当线程执行完一个任务后,它会继续从任务队列中获取下一个任务,或者进入等待状态,等待新的任务到来。如果线程在执行任务过程中发生异常,线程池会创建一个新的线程来替代它,并继续执行任务。
  4. 线程池的关闭
    • 当不再需要线程池时,可以通过线程池的shutdown方法或shutdownNow方法来关闭线程池。shutdown方法会等待线程池中所有的任务执行完毕后再关闭线程池;shutdownNow方法会立即停止线程池的执行,并尝试中断正在执行任务的线程,返回尚未执行的任务列表。

三、Java 线程池的类型与创建

(一)Java 中的线程池类型

  1. FixedThreadPool(固定大小线程池)
    • FixedThreadPool是一种固定大小的线程池,它在创建时指定了线程池的核心线程数量和最大线程数量,并且这两个数量是相等的。当有任务提交到线程池中时,如果线程池中存在空闲线程,就会立即执行任务;如果线程池中没有空闲线程,就会将任务加入到任务队列中等待执行。
    • 特点:线程数量固定,不会因为任务的增加而创建新的线程,也不会因为任务的减少而销毁线程。适用于需要限制线程数量的场景,如服务器端的连接处理。
  2. CachedThreadPool(可缓存线程池)
    • CachedThreadPool是一种可缓存的线程池,它在创建时没有指定线程池的核心线程数量和最大线程数量。当有任务提交到线程池中时,如果线程池中存在空闲线程,就会立即执行任务;如果线程池中没有空闲线程,就会创建一个新的线程来执行任务。当线程在一段时间内没有执行任务时,就会被回收。
    • 特点:线程数量不固定,可以根据任务的数量自动调整线程数量。适用于执行大量短期任务的场景,如网页爬虫。
  3. ScheduledThreadPool(定时任务线程池)
    • ScheduledThreadPool是一种用于执行定时任务的线程池,它在创建时指定了线程池的核心线程数量。当有定时任务提交到线程池中时,线程池会创建一个新的线程来执行任务,并在任务执行完毕后将线程回收。如果在任务执行过程中发生异常,线程池会创建一个新的线程来替代它,并继续执行任务。
    • 特点:可以执行定时任务和周期性任务。适用于需要定期执行任务的场景,如定时备份数据。
  4. SingleThreadExecutor(单线程线程池)
    • SingleThreadExecutor是一种单线程的线程池,它在创建时只有一个核心线程。当有任务提交到线程池中时,这个核心线程会执行任务。如果任务在执行过程中发生异常,线程池会创建一个新的线程来替代它,并继续执行任务。
    • 特点:只有一个线程在执行任务,保证任务按照提交的顺序依次执行。适用于需要保证任务顺序执行的场景,如日志记录。

(二)创建线程池的方法

  1. 使用Executors工厂类创建线程池
    • Java 提供了Executors工厂类来方便地创建不同类型的线程池。可以使用Executors.newFixedThreadPoolExecutors.newCachedThreadPoolExecutors.newScheduledThreadPoolExecutors.newSingleThreadExecutor方法分别创建固定大小线程池、可缓存线程池、定时任务线程池和单线程线程池。
    • 示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建固定大小线程池
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
        // 创建可缓存线程池
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        // 创建定时任务线程池
        ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        // 创建单线程线程池
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    }
}

  1. 使用ThreadPoolExecutor构造函数创建线程池
    • 除了使用Executors工厂类创建线程池外,还可以直接使用ThreadPoolExecutor构造函数来创建线程池。这样可以更加灵活地控制线程池的参数,如核心线程数量、最大线程数量、任务队列的类型和大小等。
    • 示例代码:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        // 创建线程池,核心线程数量为 3,最大线程数量为 5,任务队列大小为 10,任务超时时间为 1 分钟
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                3,
                5,
                1,
                TimeUnit.MINUTES,
                new ArrayBlockingQueue<>(10)
        );
    }
}

四、线程池的任务提交与执行

(一)提交任务的方法

  1. execute方法
    • execute方法用于提交一个Runnable任务到线程池中执行,没有返回值。如果线程池中的线程数量小于核心线程数量,就会创建一个新的线程来执行任务;如果线程池中的线程数量等于核心线程数量,就会将任务加入到任务队列中等待执行。
    • 示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecuteExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.execute(() -> {
            System.out.println("Task executed by thread: " + Thread.currentThread().getName());
        });
        executorService.shutdown();
    }
}

  1. submit方法
    • submit方法用于提交一个Callable任务到线程池中执行,有返回值。如果线程池中的线程数量小于核心线程数量,就会创建一个新的线程来执行任务;如果线程池中的线程数量等于核心线程数量,就会将任务加入到任务队列中等待执行。当任务执行完毕后,会返回一个Future对象,可以通过这个对象来获取任务的执行结果。
    • 示例代码:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class SubmitExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        Future<Integer> future = executorService.submit(() -> {
            System.out.println("Task executed by thread: " + Thread.currentThread().getName());
            return 42;
        });
        try {
            Integer result = future.get();
            System.out.println("Task result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }
}

(二)任务的执行过程

  1. 线程从任务队列中获取任务
    • 线程池中的线程会不断地从任务队列中获取任务并执行。如果任务队列中没有任务,线程会进入等待状态,直到有新的任务到来。当有任务提交到线程池中时,线程池会根据当前的线程状态和任务队列的情况来决定如何执行任务。
  2. 任务的执行
    • 线程获取到任务后,会执行任务中的代码。如果任务在执行过程中发生异常,线程池会创建一个新的线程来替代它,并继续执行任务。如果任务执行成功,线程会继续从任务队列中获取下一个任务,或者进入等待状态,等待新的任务到来。
  3. 任务的返回结果
    • 如果提交的任务是一个Callable任务,并且使用了submit方法提交任务,那么可以通过Future对象来获取任务的返回结果。如果任务在执行过程中发生异常,Future对象的get方法会抛出相应的异常。

五、线程池的参数调整与性能优化

(一)线程池参数的含义与调整方法

  1. 核心线程数量(corePoolSize)
    • 核心线程数量是指线程池中始终保持运行的线程数量,即使这些线程处于空闲状态。当有任务提交到线程池中时,如果线程池中存在空闲线程,就会立即执行任务;如果线程池中没有空闲线程,就会将任务加入到任务队列中等待执行。如果任务队列已满且核心线程都在忙碌时,线程池会创建新的线程来执行任务,直到线程数量达到最大线程数量。
    • 调整方法:根据任务的类型和数量来调整核心线程数量。如果任务是 CPU 密集型的,即任务主要消耗 CPU 资源,可以将核心线程数量设置为与 CPU 核心数量相等或稍大一些,以充分利用 CPU 资源。如果任务是 I/O 密集型的,即任务主要消耗 I/O 资源,可以将核心线程数量设置得较大一些,以提高线程的并发度。
  2. 最大线程数量(maximumPoolSize)
    • 最大线程数量是指线程池中允许的最大线程数量。当任务队列已满且核心线程都在忙碌时,线程池会创建新的线程来执行任务,直到线程数量达到最大线程数量。如果任务队列已满且线程数量达到最大线程数量,那么新提交的任务将被拒绝执行。
    • 调整方法:根据系统的资源情况和任务的类型来调整最大线程数量。如果系统的资源比较充足,可以将最大线程数量设置得较大一些,以提高线程的并发度。如果系统的资源比较紧张,可以将最大线程数量设置得较小一些,以避免系统资源的过度消耗。
  3. 任务队列(workQueue)
    • 任务队列是用于存储等待执行的任务的队列。当有任务提交到线程池中时,如果线程池中存在空闲线程,就会立即执行任务;如果线程池中没有空闲线程,就会将任务加入到任务队列中等待执行。
    • 调整方法:根据任务的类型和数量来选择合适的任务队列类型和大小。如果任务是 CPU 密集型的,可以选择一个较小的任务队列,以避免任务在队列中等待时间过长。如果任务是 I/O 密集型的,可以选择一个较大的任务队列,以提高线程的并发度。常见的任务队列类型有ArrayBlockingQueueLinkedBlockingQueueSynchronousQueue等。
  4. 线程空闲时间(keepAliveTime)
    • 线程空闲时间是指线程在没有任务可执行时的最大等待时间。当线程在一段时间内没有执行任务时,就会被回收。如果线程空闲时间设置得过长,可能会导致线程资源的浪费;如果线程空闲时间设置得过短,可能会导致线程频繁地创建和销毁,增加系统的开销。
    • 调整方法:根据任务的类型和数量来调整线程空闲时间。如果任务是短期任务,可以将线程空闲时间设置得较短一些,以避免线程资源的浪费。如果任务是长期任务,可以将线程空闲时间设置得较长一些,以减少线程的创建和销毁次数。
  5. 拒绝策略(rejectedExecutionHandler)
    • 拒绝策略是指当任务队列已满且线程数量达到最大线程数量时,新提交的任务将被拒绝执行时采取的策略。Java 提供了四种拒绝策略,分别是AbortPolicyCallerRunsPolicyDiscardOldestPolicyDiscardPolicy
    • 调整方法:根据系统的需求和任务的重要性来选择合适的拒绝策略。如果任务比较重要,可以选择CallerRunsPolicy,让提交任务的线程自己执行任务;如果任务不太重要,可以选择DiscardPolicyDiscardOldestPolicy,直接丢弃新提交的任务。

(二)性能优化的技巧与注意事项

  1. 合理设置线程池参数
    • 根据任务的类型和数量来合理设置线程池的参数,如核心线程数量、最大线程数量、任务队列的类型和大小等。避免设置过大或过小的参数,以免影响系统的性能和资源利用率。
  2. 避免任务阻塞
    • 在任务执行过程中,尽量避免任务的阻塞,如 I/O 操作、数据库访问等。可以使用异步 I/O、连接池等技术来减少任务的阻塞时间,提高线程的并发度。
  3. 监控线程池状态
    • 可以使用 Java 的监控工具,如jconsoleVisualVM等,来监控线程池的状态,如线程数量、任务队列大小、任务执行时间等。根据监控结果来调整线程池的参数,以提高系统的性能和资源利用率。
  4. 避免线程泄漏
    • 在任务执行过程中,要注意避免线程泄漏。线程泄漏是指线程在执行任务过程中,由于某些原因没有正确地释放资源,导致线程一直处于运行状态,无法被回收。可以使用try-with-resources语句、finally块等方式来确保资源的正确释放。
  5. 考虑任务的优先级
    • 如果任务有不同的优先级,可以考虑使用优先级队列来存储任务,以便高优先级的任务能够优先执行。Java 提供了PriorityBlockingQueue类来实现优先级队列。

六、线程池的应用场景与实际案例

(一)应用场景

  1. 网络服务器
    • 在网络服务器中,需要同时处理多个客户端的连接请求。可以使用线程池来管理连接处理线程,提高服务器的并发处理能力。当有新的连接请求到来时,从线程池中获取一个空闲线程来处理连接,连接处理完毕后,线程返回线程池等待下一个连接请求。
  2. 数据库连接池
    • 在数据库访问中,频繁地创建和销毁数据库连接会带来很大的开销。可以使用线程池来管理数据库连接,提高数据库访问的效率。当有数据库访问请求到来时,从线程池中获取一个数据库连接来执行查询操作,查询完毕后,将数据库连接返回线程池等待下一个查询请求。
  3. 任务调度
    • 在任务调度中,需要定期执行一些任务。可以使用定时任务线程池来管理任务执行线程,提高任务调度的效率。当有定时任务需要执行时,从线程池中获取一个空闲线程来执行任务,任务执行完毕后,线程返回线程池等待下一个定时任务。
  4. 并行计算
    • 在并行计算中,需要同时执行多个计算任务。可以使用线程池来管理计算任务执行线程,提高并行计算的效率。将计算任务分解为多个子任务,提交到线程池中执行,最后将子任务的结果合并得到最终的计算结果。

(二)实际案例

  1. 网络服务器案例
    • 假设我们要开发一个简单的网络服务器,能够同时处理多个客户端的连接请求。可以使用线程池来管理连接处理线程,提高服务器的并发处理能力。
    • 示例代码:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NetworkServerExample {
    public static void main(String[] args) {
        try {
            // 创建服务器套接字,监听端口 8080
            ServerSocket serverSocket = new ServerSocket(8080);
            System.out.println("服务器启动,监听端口 8080");

            // 创建线程池,核心线程数量为 5,最大线程数量为 10
            ExecutorService executorService = Executors.newFixedThreadPool(5);

            while (true) {
                // 等待客户端连接
                Socket clientSocket = serverSocket.accept();
                System.out.println("客户端连接:" + clientSocket.getInetAddress());

                // 将客户端连接处理任务提交到线程池
                executorService.execute(() -> handleClient(clientSocket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void handleClient(Socket clientSocket) {
        try {
            // 读取客户端发送的数据
            java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(clientSocket.getInputStream()));
            String request = in.readLine();
            System.out.println("收到客户端请求:" + request);

            // 处理请求并发送响应
            java.io.PrintWriter out = new java.io.PrintWriter(clientSocket.getOutputStream(), true);
            out.println("HTTP/1.1 200 OK");
            out.println("Content-Type: text/html");
            out.println();
            out.println("<html><body>Hello, World!</body></html>");

            // 关闭客户端连接
            clientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  1. 数据库连接池案例
    • 在数据库访问中,频繁地创建和销毁数据库连接会带来很大的开销。可以使用线程池来管理数据库连接,提高数据库访问的效率。
    • 示例代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class DatabaseConnectionPool {
    private static final int POOL_SIZE = 10;
    private BlockingQueue<Connection> connectionQueue;

    public DatabaseConnectionPool() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connectionQueue = new LinkedBlockingQueue<>(POOL_SIZE);
            for (int i = 0; i < POOL_SIZE; i++) {
                Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password");
                connectionQueue.add(connection);
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }

    public Connection getConnection() throws InterruptedException {
        return connectionQueue.take();
    }

    public void releaseConnection(Connection connection) {
        connectionQueue.add(connection);
    }
}

  1. 任务调度案例
    • 在任务调度中,需要定期执行一些任务。可以使用定时任务线程池来管理任务执行线程,提高任务调度的效率。
    • 示例代码:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class TaskSchedulerExample {
    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);

        // 每隔 5 秒执行一次任务
        scheduler.scheduleAtFixedRate(() -> {
            System.out.println("执行定时任务:" + System.currentTimeMillis());
        }, 0, 5, TimeUnit.SECONDS);
    }
}

  1. 并行计算案例
    • 在并行计算中,需要同时执行多个计算任务。可以使用线程池来管理计算任务执行线程,提高并行计算的效率。
    • 示例代码:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ParallelComputingExample {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            numbers.add(i);
        }

        ExecutorService executorService = Executors.newFixedThreadPool(5);
        List<Future<Integer>> futures = new ArrayList<>();

        for (Integer number : numbers) {
            Callable<Integer> task = () -> {
                return number * number;
            };
            futures.add(executorService.submit(task));
        }

        int sum = 0;
        for (Future<Integer> future : futures) {
            try {
                sum += future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }

        System.out.println("并行计算结果:" + sum);

        executorService.shutdown();
    }
}

七、结论

Java 线程池是一种非常强大的并发编程工具,它可以有效地管理和复用线程,提高系统的性能和资源利用率。在实际应用中,我们可以根据任务的类型和数量来选择合适的线程池类型,并合理调整线程池的参数,以达到最佳的性能效果。同时,我们还需要注意避免线程泄漏、任务阻塞等问题,确保线程池的稳定运行。通过合理地使用线程池,我们可以轻松地实现高并发、高性能的 Java 应用程序。

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

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

相关文章

《2024中国泛娱乐出海洞察报告》解析,垂直且多元化方向发展!

随着以“社交”为代表的全球泛娱乐市场规模不断扩大以及用户需求不断细化&#xff0c;中国泛娱乐出海产品正朝着更加垂直化、多元化的方向发展。基于此&#xff0c;《2024中国泛娱乐出海洞察报告》深入剖析了中国泛娱乐行业出海进程以及各细分赛道出海现状及核心特征。针对中国…

Python游戏开发超详细第二课/一个小游戏等制作过程(入门级篇共2节)

直播内容&#xff0c;这里都用大多用照片代替了哈&#xff0c;因为在写一遍很累&#xff0c;哥哥姐姐理解一下抱歉抱歉 一个是我懒的写一遍&#xff0c;但是刚学的兄弟姐妹可不许学我偷懒哈 二防止有人偷懒&#xff0c;直接复制粘贴代码&#xff0c;所以为了方便帮助你们学习&a…

【AIGC】ChatGPT应用之道:如何打破`专家`幻象,提升AI协作质量

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;ChatGPT的实际能力用户对ChatGPT的常见误解超越误解&#xff0c;合理设定期望总结 &#x1f4af;超越“专家”幻想设定合理的期望总结 &#x1f4af;提升人工智能协作质量…

寻找大自然的颜色

走在停停&#xff0c;停停走走&#xff0c;恍惚间一天过去了&#xff0c;转瞬间一年过去了&#xff0c;身边的一切在变化又不在变化&#xff0c;生活是自己的又不是自己的。 今天是个特殊的日子&#xff0c;其实前几天对我而言就算特殊的日子了&#xff0c;一个心里暗暗等待着却…

python之数据结构与算法(数据结构篇)-- 集合

一、集合的概念 所谓的编程中的”集合“&#xff0c;其实和高中数学中集合是一样的的。比如&#xff1a;羊村和狼堡看作一个集合&#xff0c;而狼堡中的"灰太狼"、"红太狼"、"小灰灰"则可看作狼堡中的元素&#xff0c;同理&#xff0c;羊村中的…

通过火山云API来实现:流式大模型语音对话

这里我们需要在火山云语音控制台开通大模型的流式语音对话、获取豆包模型的apiKey&#xff0c;开通语音合成项目。 这里使用的豆包模型是Doubao-lite&#xff0c;延迟会更低一些配置说明 这里一共有四个文件&#xff0c;分别是主要的fastAPI、LLM、STT、文件 TTS中需要配置 ap…

洛谷 U411986 数的范围(二分模板)

题意&#xff1a;在一个有序序列里面找某个值的初始出现下标和最后出现下标&#xff0c;如果该值不存在&#xff0c;输出-1 -1。 整数二分模板题&#xff0c;该题主要用来练习如何写两种情况下的二分函数的代码模板。 1&#xff09;upper_bound函数&#xff1a;用来寻找边界点A…

鸿蒙是必经之路

少了大嘴的发布会&#xff0c;老实讲有点让人昏昏入睡。关于技术本身的东西&#xff0c;放在后面。 我想想来加把油~ 鸿蒙发布后褒贬不一&#xff0c;其中很多人不太看好鸿蒙&#xff0c;一方面是开源性、一方面是南向北向的利益问题。 不说技术的领先点&#xff0c;我只扯扯…

香橙派5(RK3588)使用npu加速yolov5推理的部署过程

香橙派5使用npu加速yolov5推理的部署过程 硬件环境 部署过程 模型训练(x86主机) 在带nvidia显卡(最好)的主机上进行yolo的配置与训练, 获取最终的best.pt模型文件, 详见另一篇文档 模型转换(x86主机) 下载airockchip提供的yolov5(从pt到onnx) 一定要下这个版本的yolov5, …

【力扣 + 牛客 | SQL题 | 每日三题】大厂笔试真题W1,W4

1. 力扣603&#xff1a;连续空余的座位 1.1 题目&#xff1a; 表: Cinema ------------------- | Column Name | Type | ------------------- | seat_id | int | | free | bool | ------------------- Seat_id 是该表的自动递增主键列。 在 PostgreSQL 中&#…

练习LabVIEW第十九题

学习目标&#xff1a; 刚学了LabVIEW&#xff0c;在网上找了些题&#xff0c;练习一下LabVIEW&#xff0c;有不对不好不足的地方欢迎指正&#xff01; 第十九题&#xff1a; 创建一个程序把另外一个VI的前面板显示在Picture控件中 开始编写&#xff1a; 在前面板放置一个二…

C语言教程——数组(2)

目录 系列文章目录 前言 4、数组作为函数参数 4.1冒泡函数的错误设计 4.2数组名是什么&#xff1f; 总结 前言 我们知道一维数组是连续存放的&#xff0c;随着数组下标的增长&#xff0c;地址是由低到高依次存放的&#xff0c;二维数组&#xff0c;也是在内存里面是连续存放的…

Linux | 配置docker环境时yum一直出错的解决方法

yum出错 Centos 7版本出错问题补充&#xff1a;什么是yumyum 和 apt 有什么区别&#xff1f; Centos 7版本 [rootlocalhost yum.repos.d]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core)出错问题 问题1 Could not retrieve mirrorlist http://mirrorlist.ce…

SQLite 3.47.0 发布,大量新功能来袭

SQLite 开发团队于 2024 年 10 月 21 日发布了 SQLite 3.47.0 版本&#xff0c;我们来了解一下新版本的改进功能。 触发器增强 SQLite 3.47.0 版本开始&#xff0c;触发器函数 RAISE() 的 error-message 参数可以支持任意 SQL 表达式。在此之前&#xff0c;该参数只能是字符串…

论1+2+3+4+... = -1/12 的不同算法

我们熟知自然数全加和&#xff0c; 推导过程如下&#xff0c; 这个解法并不难&#xff0c;非常容易看懂&#xff0c;但是并不容易真正理解。正负交错和无穷项计算&#xff0c;只需要保持方程的形态&#xff0c;就可以“预知”结果。但是这到底说的是什么意思&#xff1f;比如和…

Nodejs使用pkg打包为可执行文件

安装pkg npm install -g pkg查看pkg命令 pkg --help修改package.json 新增bin入口配置 {"name": "takescreenshot","version": "1.0.0","bin": "app.js", // 新增bin入口配置"scripts": {"t…

day10:ssh服务-跳板机

一&#xff0c;ssh服务概述 ssh服务概述 ssh&#xff08;Secure Shell&#xff09;是一种用于在不安全网络中进行安全登录、远程执行命令及传输文件的网络协议。它通过加密技术来保证通信的保密性和完整性&#xff0c;主要用于替代不安全的telnet、rlogin、rsh等协议。ssh通常…

计算机视觉-边缘检测实验报告

实验一 边缘检测实验 一、实验目的 1&#xff0e;理解并掌握 Sobel 算子和 Canny 算子的基本原理和应用。 2&#xff0e;学习如何在图像处理中使用这两种算子进行边缘检测。 3&#xff0e;比较 Sobel 算子和 Canny 算子的性能&#xff0c;了解各自的优缺点。 4&#xff0…

【mysql进阶】4-3. 页结构

页面结构 ⻚在MySQL运⾏的过程中起到了⾮常重要的作⽤&#xff0c;为了能发挥更好的性能&#xff0c;可以结合⾃⼰系统的业务场景和数据⼤⼩&#xff0c;对⻚相关的系统变量进⾏调整&#xff0c;⻚的⼤⼩就是⼀个⾮常重要的调整项。同时关于⻚的结构也要有所了解&#xff0c;以…