首页 文章 精选 留言 我的

精选列表

搜索[java],共10000篇文章
优秀的个人博客,低调大师

Java并发编程实战系列8之线程池的使用

ThreadPoolExecutor UML图: image image 8.1 在任务和执行策略之间隐形耦合 避免Thread starvation deadlock 8.2 设置线程池大小 8.3 配置ThreadPoolExecutor image 构造函数如下: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { ... } 核心和最大池大小:如果运行的线程少于 corePoolSize,则创建新线程来处理请求(即一个Runnable实例),即使其它线程是空闲的。如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则仅当队列满时才创建新线程。 保持活动时间:如果池中当前有多于 corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止。 排队:如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列BlockingQueue,而不添加新的线程。 被拒绝的任务:当 Executor 已经关闭,或者队列已满且线程数量达到maximumPoolSize时(即线程池饱和了),请求将被拒绝。这些拒绝的策略叫做Saturation Policy,即饱和策略。包括AbortPolicy, CallerRunsPolicy, DiscardPolicy, and DiscardOldestPolicy. 另外注意: 如果运行的线程少于 corePoolSize,ThreadPoolExecutor 会始终首选创建新的线程来处理请求;注意,这时即使有空闲线程也不会重复使用(这和数据库连接池有很大差别)。 如果运行的线程等于或多于 corePoolSize,则 ThreadPoolExecutor 会将请求加入队列BlockingQueue,而不添加新的线程(这和数据库连接池也不一样)。 如果无法将请求加入队列(比如队列已满),则创建新的线程来处理请求;但是如果创建的线程数超出 maximumPoolSize,在这种情况下,请求将被拒绝。 newCachedThreadPool使用了SynchronousQueue,并且是无界的。 线程工厂ThreadFactory 8.4 扩展ThreadPoolExecutor 重写beforeExecute和afterExecute方法。 8.5 递归算法的并行化 实际就是类似Number of Islands或者N-Queens等DFS问题的一种并行处理。 串行版本如下: public class SequentialPuzzleSolver <P, M> { private final Puzzle<P, M> puzzle; private final Set<P> seen = new HashSet<P>(); public SequentialPuzzleSolver(Puzzle<P, M> puzzle) { this.puzzle = puzzle; } public List<M> solve() { P pos = puzzle.initialPosition(); return search(new PuzzleNode<P, M>(pos, null, null)); } private List<M> search(PuzzleNode<P, M> node) { if (!seen.contains(node.pos)) { seen.add(node.pos); if (puzzle.isGoal(node.pos)) return node.asMoveList(); for (M move : puzzle.legalMoves(node.pos)) { P pos = puzzle.move(node.pos, move); PuzzleNode<P, M> child = new PuzzleNode<P, M>(pos, move, node); List<M> result = search(child); if (result != null) return result; } } return null; } } 并行版本如下: public class ConcurrentPuzzleSolver <P, M> { private final Puzzle<P, M> puzzle; private final ExecutorService exec; private final ConcurrentMap<P, Boolean> seen; protected final ValueLatch<PuzzleNode<P, M>> solution = new ValueLatch<PuzzleNode<P, M>>(); public ConcurrentPuzzleSolver(Puzzle<P, M> puzzle) { this.puzzle = puzzle; this.exec = initThreadPool(); this.seen = new ConcurrentHashMap<P, Boolean>(); if (exec instanceof ThreadPoolExecutor) { ThreadPoolExecutor tpe = (ThreadPoolExecutor) exec; tpe.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); } } private ExecutorService initThreadPool() { return Executors.newCachedThreadPool(); } public List<M> solve() throws InterruptedException { try { P p = puzzle.initialPosition(); exec.execute(newTask(p, null, null)); // block until solution found PuzzleNode<P, M> solnPuzzleNode = solution.getValue(); return (solnPuzzleNode == null) ? null : solnPuzzleNode.asMoveList(); } finally { exec.shutdown(); } } protected Runnable newTask(P p, M m, PuzzleNode<P, M> n) { return new SolverTask(p, m, n); } protected class SolverTask extends PuzzleNode<P, M> implements Runnable { SolverTask(P pos, M move, PuzzleNode<P, M> prev) { super(pos, move, prev); } public void run() { if (solution.isSet() || seen.putIfAbsent(pos, true) != null) return; // already solved or seen this position if (puzzle.isGoal(pos)) solution.setValue(this); else for (M m : puzzle.legalMoves(pos)) exec.execute(newTask(puzzle.move(pos, m), m, this)); } } }

优秀的个人博客,低调大师

Java中方法重写的两个面试题

1:方法重写和方法重载的区别?方法重载能改变返回值类型吗? 方法重写: 在子类中,出现和父类中一模一样的方法声明的现象。(包含方法名、参数列表和返回值类型都一样) 方法重载: 同一个类中,出现的方法名相同,参数列表不同,与返回值类型无关的现象。 方法重载能改变返回值类型,因为它和返回值类型无关。 Override:方法重写 Overload:方法重载 2:this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。 this: 代表当前类的对象引用。 super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员。) 应用场景: 成员变量: this.成员变量 super.成员变量 构造方法: this(...) super(...) 成员方法: this.成员方法 super.成员方法我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

优秀的个人博客,低调大师

Java并发编程实战系列6之任务执行(Task Execution)

1. 在线程中执行任务 1.1 串行的执行任务 这是最经典的一个最简单的Socket server的例子,服务器的资源利用率非常低,因为单线程在等待I/O操作完成时,CPU处于空闲状态。从而阻塞了当前请求的延迟,还彻底阻止了其他等待中的请求被处理。 public class SingleThreadWebServer { public static void main(String[] args) throws IOException { ServerSocket socket = new ServerSocket(80); while (true) { Socket connection = socket.accept(); handleRequest(connection); } } private static void handleRequest(Socket connection) { // request-handling logic here } } 1.2 显式地为任务创建线程 任务处理从主线程中分离出来,主循环可以快速等待下一个连接,提高响应性。同时任务可以并行处理了,吞吐量也提高了。 public class ThreadPerTaskWebServer { public static void main(String[] args) throws IOException { ServerSocket socket = new ServerSocket(80); while (true) { final Socket connection = socket.accept(); Runnable task = new Runnable() { public void run() { handleRequest(connection); } }; new Thread(task).start(); } } private static void handleRequest(Socket connection) { // request-handling logic here } } 1.3 无限制创建线程的不足 线程的生命周期开销非常高 资源消耗。大量的空闲线程占用内存,给GC带来压力,同时线程数量过多,竞争CPU资源开销太大。 稳定性。容易引起GC问题,甚至OOM 2 Executor框架 任务就是一组逻辑工作单元(unit of work),而线程则是使任务异步执行的机制。 Executor接口,是代替Thread来做异步执行的入口,接口虽然简单,却为非常灵活强大的异步任务执行框架提供了基础。 提供了一种标准的方法将任务的提交与执行过程解耦,并用Runnable(无返回时)或者Callable(有返回值)表示任务。 Executor基于生产者-消费者模式 提交任务/执行任务分别相当于生产者/消费者,通常是最简单的实现生产者-消费者设计的方式了 2.1 基于Executor改造后的样例如下 将请求处理任务的提交与任务的实际执行解耦,并且只需采用另一种不同的Executor实现,就可以改变服务器的行为,其影响远远小于修改任务提交方式带来的影响 2.2 执行策略 这一节主要介绍做一个Executor框架需要靠那些点? 在什么线程中执行任务? 任务按照什么顺序执行?FIFO/LIFO/优先级 有多少个任务可以并发执行? 队列中允许多少个任务等待? 如果系统过载了要拒绝一个任务,那么选择拒绝哪一个?如何通知客户端任务被拒绝了? 在执行任务过程中能不能有些别的动作before/after或者回调? 各种执行策略都是一种资源管理工具,最佳的策略取决于可用的计算资源以及对服务质量的要求。 因此每当看到 new Thread(runnable).start(); 并且希望有一种灵活的执行策略的时候,请考虑使用Executor来代替 2.3 线程池 在线程池中执行任务比为每个任务分配一个线程优势明显: 重用线程,减少开销。 延迟低,线程是等待任务到达。 最大化挖掘系统资源以及保证稳定性。CPU忙碌但是又不会出现线程竞争资源而耗尽内存或者失败的情况。 Executors可以看做一个工厂,提供如下几种Executor的创建: newCachedThreadPool newFixedThreadPool newSingleThreadExecutor newScheduledThreadPool 2.4 Executor的生命周期 为解决执行服务的生命周期问题,Executor扩展了ExecutorService接口,添加了一些用于生命周期管理的方法 一个优雅停止的例子: 增加生命周期扩展Web服务器的功能 调用stop 客户端请求形式 关闭 2.5 延迟任务与周期任务 使用Timer的弊端在于 如果某个任务执行时间过长,那么将破坏其他TimerTask的定时精确性(执行所有定时任务时只会创建一个线程),只支持基于绝对时间的调度机制,所以对系统时钟变化敏感 TimerTask抛出未检查异常后就会终止定时线程(不会捕获异常) 更加合理的做法是使用ScheduledThreadPoolExecutor,只支持基于相对时间的调度 它是DelayQueue的应用场景 3 找出可利用的并行性 3.1 携带结果的任务Callable和Future Executor框架支持Runnable,同时也支持Callable(它将返回一个值或者抛出一个异常) 在Executor框架中,已提交但是尚未开始的任务可以取消,但是对于那些已经开始执行的任务,只有他们能响应中断时,才能取消。 Future非常实用,他的API如下 内部get的阻塞是靠LockSupport.park来做的,在任务完成后Executor回调finishCompletion方法会依次唤醒被阻塞的线程。 ExecutorService的submit方法接受Runnable和Callable,返回一个Future。ThreadPoolExecutor框架留了一个口子,子类可以重写newTaskFor来决定创建什么Future的实现,默认是FutureTask类。 3.2 示例:使用Future实现页面的渲染器 3.3 CompletionService: Executor与BlockingQueue 计算完成后FutureTask会调用done方法,而CompletionService集成了FutureTask,对于计算完毕的结果直接放在自己维护的BlockingQueue里面,这样上层调用者就可以一个个take或者poll出来。 3.3 示例:使用CompletionService提高渲染性能 void renderPage(CharSequence source) { final List<ImageInfo> info = scanForImageInfo(source); CompletionService<ImageData> completionService = new ExecutorCompletionService<ImageData>(executor); for (final ImageInfo imageInfo : info) completionService.submit(new Callable<ImageData>() { public ImageData call() { return imageInfo.downloadImage(); } }); renderText(source); try { for (int t = 0, n = info.size(); t < n; t++) { Future<ImageData> f = completionService.take(); ImageData imageData = f.get(); renderImage(imageData); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { throw launderThrowable(e.getCause()); } } 6.3.7 为任务设置时限 Future的get支持timeout。 6.3.8 批量提交任务 使用invokeAll方法提交List<Callable>,返回一个List<Future>

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册