首页 文章 精选 留言 我的

精选列表

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

Java并发编程的艺术(十)——线程池(1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/79612287 线程池的作用 减少资源的开销减少了每次创建线程、销毁线程的开销。 提高响应速度每次请求到来时,由于线程的创建已经完成,故可以直接执行任务,因此提高了响应速度。 提高线程的可管理性线程是一种稀缺资源,若不加以限制,不仅会占用大量资源,而且会影响系统的稳定性。因此,线程池可以对线程的创建与停止、线程数量等等因素加以控制,使得线程在一种可控的范围内运行,不仅能保证系统稳定运行,而且方便性能调优。 线程池的实现原理 线程池一般由两种角色构成:多个工作线程 和 一个阻塞队列。 工作线程工作线程是一组已经处在运行中的线程,它们不断地向阻塞队列中领取任务执行。 阻塞队列阻塞队列用于存储工作线程来不及处理的任务。当工作线程都在执行任务时,到来的新任务就只能暂时在阻塞队列中存储。 ThreadPoolExecutor的使用 创建线程池 通过如下代码即可创建一个线程池: new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, timeUnit, runnableTaskQueue, handler); 1 corePoolSize:基本线程数量它表示你希望线程池达到的一个值。线程池会尽量把实际线程数量保持在这个值上下。 maximumPoolSize:最大线程数量这是线程数量的上界。如果实际线程数量达到这个值: 阻塞队列未满:任务存入阻塞队列等待执行 阻塞队列已满:调用饱和策略 keepAliveTime:空闲线程的存活时间当实际线程数量超过corePoolSize时,若线程空闲的时间超过该值,就会被停止。PS:当任务很多,且任务执行时间很短的情况下,可以将该值调大,提高线程利用率。 timeUnit:keepAliveTime的单位 runnableTaskQueue:任务队列这是一个存放任务的阻塞队列,可以有如下几种选择: ArrayBlockingQueue它是一个由数组实现的阻塞队列,FIFO。 LinkedBlockingQueue它是一个由链表实现的阻塞队列,FIFO。吞吐量通常要高于ArrayBlockingQueue。fixedThreadPool使用的阻塞队列就是它。它是一个无界队列。 SynchronousQueue它是一个没有存储空间的阻塞队列,任务提交给它之后必须要交给一条工作线程处理;如果当前没有空闲的工作线程,则立即创建一条新的工作线程。cachedThreadPool用的阻塞队列就是它。它是一个无界队列。 PriorityBlockingQueue它是一个优先权阻塞队列。 handler:饱和策略当实际线程数达到maximumPoolSize,并且阻塞队列已满时,就会调用饱和策略。JDK1.5由四种饱和策略: AbortPolicy默认。直接抛异常。 CallerRunsPolicy只用调用者所在的线程执行任务。 DiscardOldestPolicy丢弃任务队列中最久的任务。 DiscardPolicy丢弃当前任务。 提交任务 可以向ThreadPoolExecutor提交两种任务:Callable和Runnable。 Callable该类任务有返回结果,可以抛出异常。通过submit函数提交,返回Future对象。可通过get获取执行结果。 Runnable该类任务只执行,无法获取返回结果,并在执行过程中无法抛异常。通过execute提交。 关闭线程池 关闭线程池有两种方式:shutdown和shutdownNow,关闭时,会遍历所有的线程,调用它们的interrupt函数中断线程。但这两种方式对于正在执行的线程处理方式不同。 shutdown()仅停止阻塞队列中等待的线程,那些正在执行的线程就会让他们执行结束。 shutdownNow()不仅会停止阻塞队列中的线程,而且会停止正在执行的线程。 ThreadPoolExecutor运行机制 当有请求到来时: 若当前实际线程数量少于corePoolSize,即使有空闲线程,也会创建一个新的工作线程; 若当前实际线程数量处于corePoolSize和maximumPoolSize之间,并且阻塞队列没满,则任务将被放入阻塞队列中等待执行; 若当前实际线程数量小于maximumPoolSize,但阻塞队列已满,则直接创建新线程处理任务; 若当前实际线程数量已经达到maximumPoolSize,并且阻塞队列已满,则使用饱和策略。 设置合理的线程池大小 任务一般可分为:CPU密集型、IO密集型、混合型,对于不同类型的任务需要分配不同大小的线程池。 CPU密集型任务尽量使用较小的线程池,一般为CPU核心数+1。因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。 IO密集型任务可以使用稍大的线程池,一般为2*CPU核心数。IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候去处理别的任务,充分利用CPU时间。 混合型任务可以将任务分成IO密集型和CPU密集型任务,然后分别用不同的线程池去处理。只要分完之后两个任务的执行时间相差不大,那么就会比串行执行来的高效。因为如果划分之后两个任务执行时间相差甚远,那么先执行完的任务就要等后执行完的任务,最终的时间仍然取决于后执行完的任务,而且还要加上任务拆分与合并的开销,得不偿失。

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

java中如何获得方法中的参数名

在反射的时候我们可以通过class的getParameterNames()反射获得参数的名称,但是这个名称并不是参数的真实名称,而是类似于arg0,arg1等占位名称。 下面介绍一种方法获得参数真实名称 DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer(); String[] parameterNames = discover.getParameterNames(method); 其中parameterNames就是参数的真实名称。 例如foo(string a, string b) 如果使用class.getParameterNames()会获得arg0, arg1. 而使用ParameternameDsicoverer获得的是a, b

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

Java并发编程 -- 线程安全、优先级设定

优先级设定 一个合理的优先级可以在一定条件下避免一些活跃性问题,比如死锁、饥饿等 public class Task implements Runnable{ @Override public void run() { while (true) { System.out.println(Thread.currentThread().getName() + "线程执行了..."); } } } public class PriorityTest { public static void main(String[] args) { Thread t1 = new Thread(new Task()); Thread t2 = new Thread(new Task()); /** * 设置优先级 * MAX_PRIORITY=10 * MIN_PRIORITY=1 * NORM_PRIORITY=5 */ t1.setPriority(Thread.NORM_PRIORITY); t2.setPriority(Thread.MAX_PRIORITY); t1.start(); t2.start(); } } 线程安全问题解决 当多个线程在非原子处理下操作相同的资源时,难免出现资源的混乱。 我在这里举个value++的例子。 无线程安全时 public class Task{ public int value = 0; // 没有处理线程安全 public int getValue() { return value++; } public static void main(String[] args) { Task task = new Task(); new Thread(){ @Override public void run() { while (true) { System.out.println(Thread.currentThread().getName() + " " + task.getValue()); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread(){ @Override public void run() { while (true) { System.out.println(Thread.currentThread().getName() + " " + task.getValue()); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } } image.png 我们会发现2和5有重复。这是jvm底层的问题,我在后文有分析。 处理线程安全 如果我们给线程加锁,将其变成原子处理,就会解决该问题。 public synchronized int getValue() { return value++; } 既在修饰符后加上synchronized关键字。 image.png 但是又有一个问题,这样的话,其实原理上是串行处理的,那我们该如果解决这个问题呢。

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

Java中,权限修饰符的权限测试

============================================================================= 1、 1 /* 2 权限修饰符的权限测试: 3 4 权限修饰符 本类中 同一个包下的子类和无关类 不同包下的子类 不同包下的无关类 5 private Yes No No No 6 默认 Yes Yes No No 7 protected Yes Yes Yes No 8 public Yes Yes Yes Yes 9 */ 10 11 package com.liuyi; 12 13 class Father { 14 private void show() { 15 System.out.println("show"); 16 } 17 18 void show2() { 19 System.out.println("show2"); 20 } 21 22 protected void show3() { 23 System.out.println("show3"); 24 } 25 26 public void show4() { 27 System.out.println("show4"); 28 } 29 30 public static void main(String[] args) { 31 Father f = new Father(); 32 f.show(); 33 f.show2(); 34 f.show3(); 35 f.show4(); 36 } 37 } 在本类中,测试结果为: ============================================================================= 2、 1 /* 2 权限修饰符的权限测试: 3 4 权限修饰符 本类中 同一个包下的子类和无关类 不同包下的子类 不同包下的无关类 5 private Yes No No No 6 默认 Yes Yes No No 7 protected Yes Yes Yes No 8 public Yes Yes Yes Yes 9 */ 10 11 package com.liuyi; 12 13 class Father { 14 private void show() { 15 System.out.println("show"); 16 } 17 18 void show2() { 19 System.out.println("show2"); 20 } 21 22 protected void show3() { 23 System.out.println("show3"); 24 } 25 26 public void show4() { 27 System.out.println("show4"); 28 } 29 } 1 package com.liuyi; 2 3 class Son extends Father { 4 public static void main(String[] args) { 5 Father f = new Father(); 6 //f.show(); 7 f.show2(); 8 f.show3(); 9 f.show4(); 10 System.out.println("--------------"); 11 12 Son s = new Son(); 13 //s.show(); 14 s.show2(); 15 s.show3(); 16 s.show4(); 17 } 18 } 在同一包下的子类中,测试结果为:(注意:在子类代码中分别测试了父类和子类) ============================================================================= 3、 1 /* 2 权限修饰符的权限测试: 3 4 权限修饰符 本类中 同一个包下的子类和无关类 不同包下的子类 不同包下的无关类 5 private Yes No No No 6 默认 Yes Yes No No 7 protected Yes Yes Yes No 8 public Yes Yes Yes Yes 9 */ 10 11 package com.liuyi; 12 13 class Father { 14 private void show() { 15 System.out.println("show"); 16 } 17 18 void show2() { 19 System.out.println("show2"); 20 } 21 22 protected void show3() { 23 System.out.println("show3"); 24 } 25 26 public void show4() { 27 System.out.println("show4"); 28 } 29 } 1 package com.liuyi; 2 3 class Test { 4 public static void main(String[] args) { 5 Father f = new Father(); 6 //f.show(); 7 f.show2(); 8 f.show3(); 9 f.show4(); 10 } 11 } 在同一包下的无关类中,测试结果为: ============================================================================= 4、 1 /* 2 权限修饰符的权限测试: 3 4 权限修饰符 本类中 同一个包下的子类和无关类 不同包下的子类 不同包下的无关类 5 private Yes No No No 6 默认 Yes Yes No No 7 protected Yes Yes Yes No 8 public Yes Yes Yes Yes 9 */ 10 11 package com.liuyi; 12 13 public class Father { 14 private void show() { 15 System.out.println("show"); 16 } 17 18 void show2() { 19 System.out.println("show2"); 20 } 21 22 protected void show3() { 23 System.out.println("show3"); 24 } 25 26 public void show4() { 27 System.out.println("show4"); 28 } 29 } 1 package cn.qx; 2 3 import com.liuyi.Father; 4 5 public class Son2 extends Father { //Father在com.liuyi中不是公共的,无法从外部程序包中对其进行访问,需要在class Father前面加public修饰。 6 public static void main(String[] args) { //为了简便起见,以后所有的类的前面都加public修饰。 7 Father f = new Father(); 8 //f.show(); 9 //f.show2(); 10 //f.show3(); 11 f.show4(); 12 System.out.println("--------------"); 13 14 Son2 s = new Son2(); 15 //s.show(); 16 //s.show2(); 17 s.show3(); 18 s.show4(); 19 } 20 } 在不同包下的子类中,测试结果为:(注意:在子类代码中分别测试了父类和子类) ============================================================================= 5、 1 /* 2 权限修饰符的权限测试: 3 4 权限修饰符 本类中 同一个包下的子类和无关类 不同包下的子类 不同包下的无关类 5 private Yes No No No 6 默认 Yes Yes No No 7 protected Yes Yes Yes No 8 public Yes Yes Yes Yes 9 */ 10 11 package com.liuyi; 12 13 public class Father { 14 private void show() { 15 System.out.println("show"); 16 } 17 18 void show2() { 19 System.out.println("show2"); 20 } 21 22 protected void show3() { 23 System.out.println("show3"); 24 } 25 26 public void show4() { 27 System.out.println("show4"); 28 } 29 } 1 package cn.qx; 2 3 import com.liuyi.Father; 4 5 class Test2 { 6 public static void main(String[] args) { 7 Father f = new Father(); 8 //f.show(); 9 //f.show2(); 10 //f.show3(); 11 f.show4(); 12 } 13 } 在不同包下的无关类中,测试结果为: =============================================================================我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

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应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册