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

昌平网站建设公司百度号码查询平台

昌平网站建设公司,百度号码查询平台,电子商务网站建设的基本流程,公司网站优化要怎么做线程 定义:线程是程序执行的最小单元,一个进程可以包含多个线程。创建方式: 继承 Thread 类。实现 Runnable 接口。实现 Callable 接口(带返回值)。 特点:每个线程独立运行,共享进程资源。 多…

线程

  • 定义:线程是程序执行的最小单元,一个进程可以包含多个线程。
  • 创建方式
    • 继承 Thread 类。
    • 实现 Runnable 接口。
    • 实现 Callable 接口(带返回值)。
  • 特点:每个线程独立运行,共享进程资源。

多线程任务的常见创建方式

在没有线程池的情况下,创建线程主要有以下几种方式:

(1) 继承 Thread

class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread running: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动线程}
}
  • 这种方式直接继承 Thread 类并重写 run() 方法
  • 缺点:Java 不支持多继承,如果类已经继承了其他类,则无法再继承 Thread

(2) 实现 Runnable 接口

class MyTask implements Runnable {@Overridepublic void run() {System.out.println("Task running: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyTask());thread.start(); // 启动线程}
}
  • 这种方式更灵活,因为一个类可以同时实现多个接口。
  • 需要手动创建 Thread 对象并将 Runnable 实例传递给它。

(3) 实现 Callable 接口

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;class MyTask implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println("Task running: " + Thread.currentThread().getName());return 42; // 返回结果}
}public class Main {public static void main(String[] args) throws Exception {FutureTask<Integer> futureTask = new FutureTask<>(new MyTask());Thread thread = new Thread(futureTask);thread.start();System.out.println("Result: " + futureTask.get()); // 获取返回值}
}
  • Callable 接口允许任务返回结果,并可以抛出异常。
  • 需要与 FutureTask 配合使用。

多线程

  • 定义:通过多个线程并发或并行执行任务,实现高效处理。

方式 1:直接创建多个线程

这是最基础的多线程实现方式,通过手动创建多个线程对象,并调用 start() 方法启动线程。每个线程独立运行,任务逻辑由线程执行。

实现步骤
  1. 定义任务逻辑
    • 使用 Thread 类或 Runnable 接口定义线程的任务逻辑。
  2. 创建线程对象
    • 每个任务需要对应一个线程对象。
  3. 启动线程
    • 调用线程对象的 start() 方法,启动线程并执行任务。
代码示例
方法 1:继承 Thread
class MyThread extends Thread {@Overridepublic void run() {// 线程的任务逻辑System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");}
}public class Main {public static void main(String[] args) {// 创建多个线程对象MyThread t1 = new MyThread();MyThread t2 = new MyThread();// 启动线程t1.start(); // 启动线程 1t2.start(); // 启动线程 2}
}

输出示例(顺序可能不同,因为线程是并发执行的):

线程 Thread-0 正在运行
线程 Thread-1 正在运行
方法 2:实现 Runnable 接口
class MyTask implements Runnable {@Overridepublic void run() {// 线程的任务逻辑System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");}
}public class Main {public static void main(String[] args) {// 创建多个线程对象Thread t1 = new Thread(new MyTask());Thread t2 = new Thread(new MyTask());// 启动线程t1.start(); // 启动线程 1t2.start(); // 启动线程 2}
}

输出示例(顺序可能不同):

线程 Thread-0 正在运行
线程 Thread-1 正在运行
方法 3:使用匿名内部类

如果任务逻辑简单,可以直接使用匿名内部类来简化代码:

public class Main {public static void main(String[] args) {// 使用匿名内部类创建线程new Thread(() -> {System.out.println("线程 1 正在运行");}).start();new Thread(() -> {System.out.println("线程 2 正在运行");}).start();}
}

输出示例(顺序可能不同):

线程 1 正在运行
线程 2 正在运行
关键点解析
  1. 线程启动
    • 调用 start() 方法会启动线程,并自动调用 run() 方法。
    • 不要直接调用 run() 方法,否则不会启动新线程,而是在当前线程中执行任务。
  2. 线程独立性
    • 每个线程独立运行,任务之间没有共享状态(除非显式共享变量)。
  3. 缺点
    • 频繁创建和销毁线程会导致性能开销。
    • 线程数量过多时,可能导致资源耗尽。

方式 2:使用线程池

线程池是一种更高效的多线程实现方式,通过预先创建一组线程并复用来执行任务,避免频繁创建和销毁线程。

实现步骤
  1. 创建线程池
    • 使用 Executors 工具类快速创建线程池,或者使用 ThreadPoolExecutor 自定义线程池。
  2. 提交任务
    • 将任务(RunnableCallable)提交给线程池。
  3. 关闭线程池
    • 使用 shutdown() 方法优雅地关闭线程池。
代码示例
方法 1:使用 Executors 工具类
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Main {public static void main(String[] args) {// 创建固定大小为 2 的线程池ExecutorService pool = Executors.newFixedThreadPool(2);// 提交任务pool.submit(() -> {System.out.println("任务 1 正在运行,线程:" + Thread.currentThread().getName());});pool.submit(() -> {System.out.println("任务 2 正在运行,线程:" + Thread.currentThread().getName());});// 关闭线程池pool.shutdown();}
}

输出示例(顺序可能不同):

任务 1 正在运行,线程:pool-1-thread-1
任务 2 正在运行,线程:pool-1-thread-2
方法 2:使用 ThreadPoolExecutor 自定义线程池
import java.util.concurrent.*;public class Main {public static void main(String[] args) {// 核心线程数int corePoolSize = 2;// 最大线程数int maximumPoolSize = 4;// 空闲线程存活时间long keepAliveTime = 60L;TimeUnit unit = TimeUnit.SECONDS;// 任务队列BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10);// 线程工厂ThreadFactory threadFactory = Executors.defaultThreadFactory();// 拒绝策略RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);// 提交任务for (int i = 1; i <= 5; i++) {final int taskId = i;executor.submit(() -> {System.out.println("任务 " + taskId + " 正在运行,线程:" + Thread.currentThread().getName());});}// 关闭线程池executor.shutdown();}
}

输出示例(顺序可能不同):

任务 1 正在运行,线程:pool-1-thread-1
任务 2 正在运行,线程:pool-1-thread-2
任务 3 正在运行,线程:pool-1-thread-1
任务 4 正在运行,线程:pool-1-thread-2
任务 5 正在运行,线程:pool-1-thread-1
关键点解析
  1. 线程复用
    • 线程池中的线程会被复用,减少线程创建和销毁的开销。
  2. 任务队列
    • 当线程池中的线程都在忙碌时,新任务会被放入任务队列等待。
  3. 拒绝策略
    • 如果任务队列已满且线程池达到最大线程数,新任务会被拒绝,触发拒绝策略。
  4. 优雅关闭
    • 使用 shutdown() 方法可以等待所有任务完成后关闭线程池。
    • 使用 shutdownNow() 方法会尝试立即停止所有任务。

直接创建多个线程适合小规模任务,使用线程池适合大规模任务或需要高效管理线程的场景。


线程池

  • 定义:一种管理线程的工具,预先创建一组线程,复用它们来执行多个任务,旨在提高程序性能和资源利用率。
  • 优点
    • 避免频繁创建和销毁线程,减少性能开销。
    • 提供任务队列、拒绝策略等高级功能。
  • 常见线程池
    • 固定大小线程池:Executors.newFixedThreadPool(n)
    • 单线程池:Executors.newSingleThreadExecutor()
    • 可缓存线程池:Executors.newCachedThreadPool()
    • 定时任务线程池:Executors.newScheduledThreadPool(n)

在 Java 中,java.util.concurrent 包提供了多种方式来创建和管理线程池,以下是几种常见的线程池创建方法:

1. 使用 Executors 工具类

Executors 是一个线程池工厂类,提供了多种静态方法来创建不同类型的线程池。这些方法简单易用,但在某些场景下可能导致资源浪费或性能问题(如固定大小的线程池可能导致任务堆积)。

(1) 创建固定大小的线程池

ExecutorService executor = Executors.newFixedThreadPool(5);
  • 特点:线程池中始终保持固定数量的线程(这里是 5 个),超出任务会被放入队列等待
  • 适用场景:适用于任务量相对稳定、需要控制并发数的场景。

(2) 创建单线程的线程池

ExecutorService executor = Executors.newSingleThreadExecutor();
  • 特点:线程池中只有一个线程,所有任务按顺序执行
  • 适用场景:适用于需要保证任务按顺序执行且无需并发的场景。

(3) 创建可缓存的线程池

ExecutorService executor = Executors.newCachedThreadPool();
  • 特点:线程池会根据需要动态创建线程,空闲线程会被回收(默认 60 秒无任务时回收)。
  • 适用场景:适用于大量短期异步任务的场景,但不适合长期运行的任务,因为可能会导致线程过多。

(4) 创建定时任务线程池

ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
  • 特点:支持定时任务和周期性任务
  • 适用场景:适用于需要调度任务的场景。

2. 使用 ThreadPoolExecutor 手动创建线程池

虽然 Executors 提供了便捷的线程池创建方法,但在实际开发中,推荐使用 ThreadPoolExecutor 来手动创建线程池,因为它提供了更细粒度的配置选项

示例代码:

import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 核心线程数int corePoolSize = 5;// 最大线程数int maximumPoolSize = 10;// 空闲线程存活时间long keepAliveTime = 60L;// 时间单位TimeUnit unit = TimeUnit.SECONDS;// 任务队列BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);// 线程工厂ThreadFactory threadFactory = Executors.defaultThreadFactory();// 拒绝策略RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);// 提交任务for (int i = 0; i < 10; i++) {final int taskId = i;executor.submit(() -> {System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());});}// 关闭线程池executor.shutdown();}
}

参数解析:

  1. corePoolSize:核心线程数,线程池中保持的最小线程数
  2. maximumPoolSize:最大线程数,当任务队列满时,线程池最多可以扩展到的线程数
  3. keepAliveTime空闲线程的存活时间,超过这个时间后,多余的非核心线程会被回收。
  4. unitkeepAliveTime时间单位
  5. workQueue任务队列,用于存放待执行的任务
  6. threadFactory线程工厂,用于创建线程。
  7. handler拒绝策略,当线程池无法处理新任务时的处理方式。

3. 常见的拒绝策略

当线程池和任务队列都满时,新的任务将被拒绝,此时会触发拒绝策略。以下是几种常见的拒绝策略:

  • AbortPolicy(默认):抛出 RejectedExecutionException 异常
  • CallerRunsPolicy:由调用线程执行该任务。
  • DiscardPolicy直接丢弃任务,不抛异常。
  • DiscardOldestPolicy丢弃队列中最老的任务,然后尝试重新提交新任务。

什么是拒绝策略?

当线程池和任务队列都已满时(即:1. 线程池中的线程数已经达到最大线程数。2. 任务队列已满),新的任务无法被处理。此时,线程池会根据配置的 拒绝策略 决定如何处理新提交的任务。

拒绝策略具体应用

1. AbortPolicy(默认策略)
  • 行为:直接抛出 RejectedExecutionException 异常,表示任务被拒绝。
  • 代码示例
    ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() // 默认策略
    );executor.submit(() -> {try {Thread.sleep(1000); // 模拟任务耗时} catch (InterruptedException e) {}System.out.println("Task 1");
    });executor.submit(() -> System.out.println("Task 2"));
    executor.submit(() -> System.out.println("Task 3")); // 超过容量,触发拒绝策略
    
  • 输出结果
    Task 1
    Task 2
    Exception in thread "main" java.util.concurrent.RejectedExecutionException: ...
    
  • 适用场景
    • 希望在任务无法执行时立即发现问题并处理异常。
    • 适用于对任务丢失零容忍的场景。
2. CallerRunsPolicy
  • 行为:由调用线程(提交任务的线程)执行该任务。
  • 代码示例
    ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy()
    );executor.submit(() -> {try {Thread.sleep(1000); // 模拟任务耗时} catch (InterruptedException e) {}System.out.println("Task 1");
    });executor.submit(() -> System.out.println("Task 2"));
    executor.submit(() -> System.out.println("Task 3")); // 超过容量,由主线程执行
    
  • 输出结果
    Task 1
    Task 2
    Task 3
    
  • 特点
    • 提交任务的线程(如主线程)会被阻塞,直到它完成任务的执行。
    • 这是一种“降级”机制,可以防止任务丢失。
  • 适用场景
    • 适用于任务量波动较大的场景,允许任务稍微延迟执行
    • 不适合对性能要求极高的场景,因为调用线程可能会被阻塞。
3. DiscardPolicy
  • 行为:直接丢弃任务,且不抛出任何异常。
  • 代码示例
    ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy()
    );executor.submit(() -> {try {Thread.sleep(1000); // 模拟任务耗时} catch (InterruptedException e) {}System.out.println("Task 1");
    });executor.submit(() -> System.out.println("Task 2"));
    executor.submit(() -> System.out.println("Task 3")); // 被丢弃,无任何提示
    
  • 输出结果
    Task 1
    Task 2
    
  • 特点
    • 任务被静默丢弃,不会有任何反馈
    • 适用于对任务丢失不敏感的场景。
  • 适用场景
    • 任务优先级较低,或者任务丢失对系统影响较小的情况。
    • 不适合需要高可靠性的场景。
4. DiscardOldestPolicy
  • 行为:丢弃任务队列中最老的任务(最早进入队列的任务),然后尝试重新提交当前任务。
  • 代码示例
    ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy()
    );executor.submit(() -> {try {Thread.sleep(1000); // 模拟任务耗时} catch (InterruptedException e) {}System.out.println("Task 1");
    });executor.submit(() -> System.out.println("Task 2"));
    executor.submit(() -> System.out.println("Task 3")); // 触发 DiscardOldestPolicy
    
  • 输出结果
    Task 1
    Task 3
    
  • 特点
    • 最老的任务被丢弃,新任务有机会被执行。
    • 可能导致某些任务永远无法执行。
  • 适用场景
    • 任务有时间敏感性,较新的任务比旧任务更重要
    • 不适合对任务完整性有严格要求的场景。

触发条件

拒绝策略会在以下情况下触发:

  1. 线程池已达到最大线程数:线程池中的线程都在忙碌。
  2. 任务队列已满:新任务无法加入队列等待。

总结对比

策略名称行为适用场景
AbortPolicy抛出异常,拒绝任务需要快速发现问题并对异常进行处理的场景
CallerRunsPolicy由调用线程执行任务允许任务稍有延迟,但不能丢失的场景
DiscardPolicy静默丢弃任务对任务丢失不敏感的场景
DiscardOldestPolicy丢弃最老的任务,重试新任务新任务比旧任务更重要的场景

4. 注意事项

  1. 避免使用 Executors 默认线程池
    Executors 提供的线程池在某些场景下可能导致内存泄漏或性能问题,例如 newFixedThreadPoolnewSingleThreadExecutor 使用的是无界队列,可能会导致任务堆积,最终耗尽内存。

  2. 合理设置线程池参数
    根据任务类型(CPU 密集型或 I/O 密集型)和硬件资源(CPU 核心数)合理设置线程池大小。例如:

    • CPU 密集型任务:线程数 ≈ CPU 核心数 + 1。
    • I/O 密集型任务:线程数可以适当增加,以充分利用等待时间。
  3. 及时关闭线程池
    使用完线程池后,务必调用 shutdown()shutdownNow() 方法释放资源。

5. 线程池中的任务提交方式

在线程池中,任务的提交方式主要依赖于 RunnableCallable 接口,而不是直接创建线程。以下是两种常见的任务提交方式:

(1) 提交 Runnable 任务

ExecutorService executor = Executors.newFixedThreadPool(5);executor.submit(() -> {System.out.println("Task running: " + Thread.currentThread().getName());
});executor.shutdown();
  • Runnable 任务不返回结果,适用于不需要获取任务执行结果的场景。

(2) 提交 Callable 任务

ExecutorService executor = Executors.newFixedThreadPool(5);Future<Integer> future = executor.submit(() -> {System.out.println("Task running: " + Thread.currentThread().getName());return 42; // 返回结果
});System.out.println("Result: " + future.get()); // 获取返回值executor.shutdown();
  • Callable 任务返回结果,适用于需要获取任务执行结果的场景。
  • Future 对象用于获取任务的返回值或检查任务状态

使用线程池时,不需要手动创建线程。线程池已经为你管理了线程的生命周期,你只需要关注任务逻辑即可。具体来说:

  • 如果任务实现了 Runnable 接口,可以通过 submit()execute() 方法提交任务。
  • 如果任务实现了 Callable 接口,可以通过 submit() 方法提交任务,并通过 Future 获取结果

换句话说,在使用线程池的情况下,传统的创建线程的方式(如继承 Thread 类或直接创建 Thread 对象)已经被线程池的机制所取代。


关系总结

  • 线程 是基础,是多线程的基本组成单位。
  • 多线程 是目标,通过多个线程并发执行任务。
  • 线程池 是多线程的优化工具,用于高效管理线程。

为什么推荐使用线程池?

  1. 性能优化
    线程的创建和销毁开销较大,线程池通过复用线程显著减少了这种开销。

  2. 资源控制
    线程池可以限制并发线程数,避免系统资源耗尽。

  3. 任务管理
    线程池提供了任务队列、拒绝策略等机制,方便管理和调度任务。

  4. 代码简洁
    使用线程池后,代码更加清晰,无需手动管理线程的生命周期。

通俗比喻

  • 线程:像工人,负责干活。
  • 多线程:雇佣多个工人同时干活。
  • 线程池:提前组建一个工人团队,按需分配任务,避免频繁招聘和辞退。

线程是基础,多线程是目标,线程池是实现多线程的高效工具。

http://www.dtcms.com/wzjs/366204.html

相关文章:

  • 淘宝网站建设服务类目选择如何解决网站只收录首页的一些办法
  • 近几年的网络营销案例优化大师电脑版官方
  • ps网站怎么做滑动背景图片下载优化大师安装桌面
  • 那家公司做网站百度推广开户费用标准
  • 电子商务建立网站前期准备百度百科推广费用
  • 去除 做网站就用建站之星外链推广软件
  • 自己做网站引用别人的电影优化关键词怎么做
  • 网站建设的流程图示网站优化排名推荐
  • 网站系统维护免费发布信息网平台
  • 公司的网站建设价格低广东seo网站优化公司
  • 专业网站制作公司案例优化网站的步骤
  • 北京网站建设公司册网站设计公司哪家专业
  • 做外贸上阿里巴巴什么网站口碑推广
  • wordpress主题合并插件网络推广优化招聘
  • 免费下载网站软件seo什么意思简单来说
  • 上海市住房与城乡建设委员会网站专业seo外包
  • 做网站的中标公司百度云网盘搜索引擎
  • 企业网站制作教程视频百度投广告怎么收费
  • 数据分析和网站开发松松软文
  • 凡科网站源码下载长春网站建设技术托管
  • 微网站建设比较全面的是谷歌广告联盟怎么做
  • 高端网站建设公司排行电商营销策划方案范文
  • 怎样做生成的二维码链接到网站怎样联系百度客服
  • 南通网站推广排名谷歌搜索引擎首页
  • 网站开发的英文书有什么链接提取视频的网站
  • 简单网站建设运营广州最新消息
  • 网站建设策划书范文6篇全免费建立自己的网站
  • 做英文网站怎么赚钱网站出租三级域名费用
  • 如何开通微信公众号昆明网站seo公司
  • 做自己头像的网站网站推广哪家好