首页 文章 精选 留言 我的

精选列表

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

Java 基础 之 continue和 break

http://www.verejava.com/?id=17159306674727 public class Test2 { public static void main(String[] args) { for (int i = 1; i <= 64; i++) { //如果 i==13 当前循环不执行, 继续执行后面的循环 if (i == 13) { continue; //终止当前循环, 继续后面的循环 } if (i == 20) { break; //终止退出循环, 后面的循环不会再执行 } System.out.print("*" + i); if (i % 8 == 0) { System.out.println(""); } } } } http://www.verejava.com/?id=17159306674727

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

Java并发编程LockSupport使用实例

最近负责的项目需要实现一个Web页面监控功能,待监控的数据需要从数据库中统计出来。本身来讲这是一个很简单的功能点,但是考虑到监控端页面会被多人同时访问的业务场景,监控数据又要求每间隔一秒刷新一次,如果每个监控界面都实时去访问数据库,那么数据库的资源开销就太大了,若在白天的业务繁忙期遇到监控端用户数较多时有可能会影响正常的交易办理。为了避免数据库资源过度使用的问题我的设计是在web容器后台构建一块监控数据缓存,无论前台有多少个人访问监控页面,都只是从web容器缓存中获取监控数据,web容器后台有一个值守线程X每间隔一秒访问数据库轮询监控数据至内存中,示意图如下: 屏幕快照 2018-07-27 下午4.50.43.png 仅仅实现以上业务流程其实也非常简单,还用不上LockSupport支持,但是本着对系统资源的最低能耗及高性能需求,我有了更进一步的优雅实现愿景,当没有User监控请求访问容器时后台值守线程可以不干活让其处于阻塞状态,当容器收到User端监控请求时后台值守线程X立即从阻塞状态转变成Running状态,为此我们需要学习运用concurrent包中的LockSupport类来控制多线程间的运行状态切换以实现需求 LockSupport学习 LockSupport是JDK中比较底层的类,用来创建锁和其他同步工具类的基本线程阻塞原语。LockSupport很类似于二元信号量(只有1个许可证可供使用),如果这个许可还没有被占用,当前线程获取许可并继续执行;如果许可已经被占用,当前线程阻塞,等待获取许可。通过网上一些对LockSupport的源码分析可知,其实现是通过调用本地代码(C++)来做的,具有很强的OS平台相关性,因此性能应该是非常高的。对于JVM应用来说主要是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒操作的,当然实现线程间的阻塞和唤醒我们还可以用到对象锁,通过Synchronizer关键字来实现对象同步锁,使用对象的wait()和notify()方法来实现,但是此方式的实现在性能上会大打折扣而且有些并发控制不当非常容易引发线程间死锁,可以说非常不优雅。 LockSupport类核心方法 基于Unsafe类中的park和unpark方法 public static void park() { UNSAFE.park(false, 0L); } public static void unpark(Thread thread) { if (thread != null) UNSAFE.unpark(thread); } park()方法,调用native方法阻塞当前线程 unpark()方法,唤醒处于阻塞状态的线程Thrread LockSupport类测试Demo 如下编写一个ThreadPark类来验证park与unpark方法的成对使用 public class ThreadParkTest { public static void main(String[] args) { MyThread mt = new MyThread(); mt.setName("mt"); mt.start(); try { Thread.currentThread().sleep(10); mt.park(); Thread.currentThread().sleep(10000); mt.unPark(); Thread.currentThread().sleep(10000); mt.park(); } catch (InterruptedException e) { e.printStackTrace(); } } static class MyThread extends Thread { private boolean isPark = false; public void run() { System.out.println(" Enter Thread running....."); while (true) { if (isPark) { System.out.println(Thread.currentThread().getName()+"Thread is Park....."); LockSupport.park(); } //do something System.out.println(Thread.currentThread().getName()+">> is running"); try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void park() { isPark = true; } public void unPark() { isPark = false; LockSupport.unpark(this); System.out.println("Thread is unpark....."); } } } 程序运行输出: Enter Thread running..... mt>> is running mt>> is running mt>> is running mt>> is running mt>> is running mtThread is Park..... Thread is unpark..... mt>> is running mt>> is running mt>> is running mt>> is running mt>> is running mt>> is running mt>> is running mt>> is running mt>> is running mt>> is running mtThread is Park park翻译过来即是停车的意思,我们可以这样理解,每个被应用程序启动的线程就是一辆在计算机总线赛道上奔驰着的跑车,当你想让某台车停下来休息会时那么就给它一个park信号,它就会立即停到赛道旁边的停车位中,当你想让它从停车位中驶出并继续在赛道上奔跑时再给它一个unpark信号即可 LockSupport的业务实际应用 我们对技术基础知识的掌握是为了更好,更优雅,更从容的实现业务需求,以最小的程序代价来实现业务最大收益化是计算机软件工程的永恒追求主题之一。 差不多给自己埋好坑了(围笑),不扯淡了,还是show me the code吧。 回到第一章的监控业务需求,首先我们需要编写后台值守线程X类,Daemon线程类Run()方法中除实现从数据库中加载监控数据到内存之外还必须实现具备满足一定条件时调用park()方法线程自动停车,同时对外要提供unpack()方法用于外部唤醒线程。 后台值守线程MonitorWorkThread类代码编写: class MonitorWorkThread extends Thread { //当前线程停车标志 private volatile boolean isPark = false; //工作线程默认一秒钟加载一次,count即为工作监控线程每一次unpack之后会继续工作的时间,此值可根据实际需求配置化 private int maxWorkCount = 300; @Override public void run() { int indexCount=0; logger.info("成功启动审核任务监控工作线程,当前工作线程每次unpack连续工作的时间设定为"+maxWorkCount+"秒"); while(true) { if(indexCount >= maxWorkCount) { logger.info("当前监控工作线程已到达连续工作时间设定上限,现在进入pack休眠状态"); isPark =true; indexCount=0; LockSupport.park(); } //从数据库中加载数据至内存 try { loadDataFromDB(); } catch (Exception e1) { logger.warn("从数据库中加载监控数据至内存发生异常", e1); } try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { logger.warn("工作线程被异常中断唤醒", e); } indexCount++; } } /** * 假如当前线程正在运行状态,donothing */ public void unPack() { if(isPark) { //唤醒当前监控工作线程,此处有并发唤醒动作需加锁 synchronized (this) { isPark = false; LockSupport.unpark(this); logger.info("当前监控工作线程已被唤醒"); } } } } 接下来我们考虑编写监控业务实现类,大体思路是我们先需要定义内存缓存map用于装载数据库监控数据,业务实现类在容器实例化时自动启动上面的值守线程MonitorWorkThread,对外提供一个获取内存数据的公共方法,公共方法体中需要调用值守线程的unPack()方法以实现当容器收到客户端监控访问请求时若后台异步值守线程处于停车(阻塞)状态时,会被唤醒继续奔跑上路。任务监控业务实现类TaskMonitorServiceImpl编写: /** * * @author lyp * 审核任务监控实现类 */ @Service("TaskMonitorServiceImpl") public class TaskMonitorServiceImpl { private static Logger logger= Logger.getLogger(TaskMonitorServiceImpl.class); //总任务状态缓存表 private List<TaskStatusBean> totalStatus = new ArrayList<TaskStatusBean>(); //审核柜员任务处理缓存表 private Map<String,UserTaskCountDto> userTaskMap = new ConcurrentHashMap<String, UserTaskCountDto>(); //监控工作线程引用 private static MonitorWorkThread workThread=null; @PostConstruct private void initalizal() { //实例化之后执行的初始化动作,用于启动值守监控线程来刷新加载数据 workThread = new MonitorWorkThread(); workThread.setDaemon(true); workThread.setName("AuthTaskMonitor"); workThread.start(); } /** * 此为对外提供方法用于外部根据监控用户号获取内存中缓存的监控数据 * @param userno 监控用户号 * @return map key1:totalStatus key2:userno * @throws Exception */ public Map<String,Object> monitorDataByUser(String userno) throws Exception { if(null == userno || "".equals(userno)) { return null; } Map<String,Object> retMap = new HashMap<String, Object>(); if(null !=workThread) { //每次请求都去看看异步值守线程是否需求唤醒 workThread.unPack(); } retMap.put("totalStatus", totalStatus); if(userTaskMap.containsKey(userno)) { retMap.put(userno, userTaskMap.get(userno)); }else { UserTaskCountDto dto = new UserTaskCountDto(userno); retMap.put(userno, dto); } return retMap; } /** * 从数据库中加载内存数据至内存 */ private void loadDataFromDB () throws Exception { logger.info("开始从数据库中加载任务监控数据..."); //do something about business.... logger.info("从数据库中加载任务监控数据完毕..."); } /** * 清理监控缓存数据map */ public void clearMonitorCache() { this.totalStatus.clear(); this.userTaskMap.clear(); } } 写在最后 技术知识的学习本身就是枯燥无味的,靠解决问题的动力来驱动技术知识的掌握未尝不是一个值得尝试的高效学习方法。以上是我第一次在简书书写文章,选择加入简书的原因其实很简单,一是看美剧的时候被大量广告植入,二是简书的编辑器完美支持MarkDown语言写作。其实这也是我第一次使用MarkDown标记语言写作排版,MarkDown的写作方式对于程序员来说真的是太爽了,啊啊啊。MarkDown语言 Markdown is intended to be as easy-to-read and easy-to-write as is feasible. Readability, however, is emphasized above all else. A Markdown-formatted document should be publishable as-is, as plain text, without looking like it's been marked up with tags or formatting instructions. Markdown's syntax is intended for one purpose: to be used as a format for writing for the web 写作不易,看完本文如果你觉得对你的工作生活有帮助请给个赞赏,不在乎多少,这会给予我写作无限的动力。 最后如果你需要转载此文,请标明原创出处,谢谢。

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

Java面试技巧和重点分析

一.前言 虽然本人也是刚入行不久,但是之前也做过一些面试准备,刚好7--8月份,还有部分学生或者初入开发行业的潜在同行,正在找工作,所以把自己的感触分享给大家,希望能够帮助到大家,能够顺利的通过面试笔试,进入自己心仪的公司。 二.重点 做为一名应届生或者初入开发行业人员,应该注重基础知识和一些框架工具的使用。 2.1:基础知识是系统原理和算法之类的,对这些原理理解的深度很重要,因为这是一种思维方式,所有的语言底层原理都差不多;一个人的技术上限是由他的基础决定的,在面试官面前展现的基础越扎实给面试官留下的印象更好。 2.2:对框架工具的了解不说是所有的,但是针对目前主流的框架不说了解的很清楚,但是也应该知道一些,比如SSH、SpringBoot、SpringCloud这些框架你需要知道他们的使用和他们核心的实现原理。比如Spring,你要知道 ioc , aop 和他的工厂是怎么实现的吧?这个东西你平时不去深究,你使用再久Spring可能都不知道原理。但是你不去了解先进技术的实现原理你怎么可能研究出新的技术和框架? 2.3:知识的了解不应该只浮于表面,应该有深度和广度。这点在我进入公司工作之前我没有任何认知,但是在进入公司后和领导、同事接触后,深深的发现自己对知识积累点的单薄,可能有的人会说,这些基础的东西这么简单,我早就学会了,平时一直都在写,没必要去专门再学。但是这样的,请问,天天在用String的你,知道它的实现,能理解应用那些设计模式吗? 在面对面试官的时候,你永远不会知道他的下一个问题是什么,所以对知识点的储存,深挖永远都没有错,总结一下就是,打好基础底子,千万不要飘,深入学习,这样你面对面试官的时候,才能有更多的可以聊的话题,从容面对面试官的话题,更快的融入公司。 三.总结 以上我个人看法,并不一定是正确的。每个人的想法都不一样,毕竟自己目前也还是一个菜鸟,希望和大家在学习的道路上共同进步,另外以下是总结的一些面试题目,有兴趣可以看下,谢谢 1、 面向对象的特征有哪些方面?答:面向对象的特征主要有以下几个方面:- 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。- 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。- 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。- 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:1). 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2). 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。 2、 float f=3.4;是否正确?答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。 3、 :成员变量与局部变量的区别? 成员变量:有类成员变量(有static修饰)和实例成员变量(无static修饰)两种 局部变量:有代码块局部变量,形参,方法局部变量三种 区别:作用范围不同,成员变量对整个类有效,局部变量只对该方法或代码块有用定义成员变量是可以不初始化,局部变量除了形参之外,必须初始化 4、 Equals与 == 的区别 ==既可以比较基本类型,也可以比较引用类型,比较引用类型时,必须是父子关系 equals只能比较引用类型,比较是地址 5、 接口与抽象类的区别 区别:相同点: 1,都不能实例化 2,都有抽象方法不同点: 1,接口只能定义常量,抽象类既可以定义常量也可以定义变量 2,接口里没有构造器和初始化块,抽象类有构造器和初始化块 3,接口里只有抽象方法,抽象类里有抽象方法和普通方法 4,接口可以实现多个,抽象类的继承只能继承一个 5,接口只能实现接口,不能实现其他类,抽象类即可实现接口,也可继承其他类 6,接口定义用interface,抽象类定义用extends

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

Java 基础 之 三目运算

http://www.verejava.com/?id=16992606159717 public class Operation6 { public static void main(String[] args) { //三目运算 int score=90; String result=score>=60?"及格":"不及格"; System.out.println(result); } } /* 回顾总结 运算分为: 1.算数运算 包括 +,-,*,/,%,++,-- 2.赋值运算 =,+=,-=,%=,/=,*= 3.逻辑运算 &&,||,! 4.关系运算 >,>=,<,<=,!=,== 5.位运算 &,|,~,^,<<,>>,>> 6.字符串连接 + 7.三目运算 ? : */ http://www.verejava.com/?id=16992606159717

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

Java 基础 之 逻辑运算

http://www.verejava.com/?id=16992598459515 public class Operation4 { public static void main(String[] args) { //逻辑运算 /* 包括: 与&&(and) ,或||(or) 非! 1. && 当操作两边都为true时返回结果为true,否则为false 2. || 当操作两边都为false时返回结果为false,否则为true; 3. ! 取反,操作为true返回结果false,否则为true */ System.out.println(true&&false); System.out.println(false&&true); System.out.println(false&&false); System.out.println(true&&true); System.out.println("---------------"); System.out.println(true||false); System.out.println(false||true); System.out.println(true||true); System.out.println(false||false); System.out.println("---------------"); System.out.println(!true); System.out.println(!false); // ! 是单目运算 //System.out.println(true!false); System.out.println("----------------"); boolean b=true; System.out.println(b); System.out.println(1>2&&(b=3>4)); System.out.println(b); System.out.println(2>1&&(b=3>4)); System.out.println(b); /* 注意: &&的短路特性: 因为程序是从上往下,从左往右执行的,当判断左边为false时 &&的返回结果就已经注定是false ,所以后面的判断计算机就不执行了. */ System.out.println("--------------"); boolean b1=true; System.out.println(b1); System.out.println(2>1||3>4); System.out.println(2>1||(b1=3>4)); System.out.println(b1); System.out.println(1>2||(b1=3>4)); System.out.println(b1); /* 注意: || 的短路特性:因为程序是从左往右执行,当判断左边为true时 返回结果就已经注定是 true, 所以后面的判断计算机不执行 */ } } http://www.verejava.com/?id=16992598459515

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

Java 基础 之 常量类型转换

http://www.verejava.com/?id=16992572054911 /* 类型转换分为以下几种情况 1. 整型类型转换 2. 浮点类型转换 3. 布尔类型转换 4. 字符类型转换 */ public class TypeConvert { public static void main(String[] args) { byte a1=1; int b1=2; //小整数类型转换成大整数类型, 直接转换 b1=a1; System.out.println(b1); byte a2=1; int b2=2; int b3=128; //大整数类型转换成小整数类型, 需要强制类型转换, 并且可能损失精度. 将会把高位切除. a2=(byte)b2; a2=(byte)b3; System.out.println(a2); byte c1=1; float c2=10.3f; //整数转浮点型,直接转换 c2=c1; System.out.println(c2); byte d1=1; float d2=10.3f; float d3=128.2f; //浮点类型转整型 直接去掉小数部分, 需要强制类型转换, 并且可能丢失精度 d1=(byte)d2; d1=(byte)d3; System.out.println(d1); //布尔类型不能转换成其他类型, 其他类型也不能转换成布尔类型 boolean e1=true; //e1=(boolean)1; char f1='a'; int f2=1; char f3='b'; int f4='b'+1; char f5='b'+1; //整型可以转换成 字符类型,需要强制类型转换,整型也可以转换成字符型,转换的规则为 ACSII 码表 f1=(char)f2; f2=f3; System.out.println(f1); System.out.println(f2); System.out.println(f4); System.out.println(f5); //字符串连接 + 转换 String str="hello"; String str2=str+1; String str3=str+2.5; String str4=str+true; String str5=str+'F'; //字符串跟其他基本类型相加 其他类型自动转换成字符串连接 System.out.println(str2); System.out.println(str3); System.out.println(str4); System.out.println(str5); } } /* 总结: 1. 类型转换小数值到大数值转换 byte<short<int<float<long<double 2. 整型 默认是 int 型, 浮点型 默认是 double 型 */ http://www.verejava.com/?id=16992572054911

资源下载

更多资源
优质分享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应用均可从中受益。

Rocky Linux

Rocky Linux

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

用户登录
用户注册