自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(169)
  • 问答 (2)
  • 收藏
  • 关注

原创 凯利判据原理及证明 - 为什么不要All In

凯利判据的原理及证明为什么你永远不要All In

2023-03-13 09:56:54 600 2

原创 Java序列化攻击和最佳实践

85. 其他序列化优于Java序列化Java序列化机制很危险,在新编写的系统中,没有理由再使用Java序列化,应该使用其他序列化机制,例如跨平台的JSON序列化;尤其不要反序列化任何不信任的数据,因为容易遭受序列化攻击。原因在于,反序列化不被信任的数据,容易受到序列化攻击,例如远程代码执行(RCE),拒绝服务(DoS)等等。研究人员可以基于Java序列化机制开发出很多巧妙的攻击片段。例如:public class BombSerializable { public static void

2022-04-29 09:36:47 462

原创 深入理解Java序列化机制

默认序列化方法基本形式基本形式非常简单,要让类支持序列化,只需要实现Serializable接口即可,该接口是一个标记接口。序列化的类的所有实例域必须都是可序列化的,也就是说,实例域为引用类型,则该类型也必须实现Serializable。public class WriteObject { public static void main(String[] args) { try (ObjectOutputStream oos = new ObjectOutputStream(

2022-04-24 22:02:41 279

原创 Java并发中的种种正确的Tips

78. 同步访问共享的可变数据本条主要是指出内存可见性,Java内存模型,重排序等机制引起可变对象共享的问题,这些都是并发的基础理论知识。有时候这些错误不容易分析:// Broken! - How long would you expect this program to run?public class StopThread { private static boolean stopRequested; public static void main(String[] args)

2022-04-12 11:04:15 190

原创 你真的懂得Java异常的正确使用姿势吗?

引言异常机制我们再熟悉不过,在开发环境中,它非常有用。它能帮我们的程序从错锁中恢复,也能在程序奔溃的时候方便我们定位异常原因。但大家在生产环境中会不会有这种感觉:这个异常究竟应该catch处理掉呢,还是应该抛给调用方?底层抛出来的异常,究竟在哪一层处理比较好?应该抛出什么异常?尽管我们会想,属于用户责任就应该抛给用户,但这里的边界,实际开发中很难界定。本文来回答这个问题,并且会给出异常机制相关的最佳实践。回忆一下异常的知识。其中:Error是严重的错误,例如内存耗尽,栈溢出等等,它属于非受检异

2022-04-03 15:12:41 345

原创 原子变量、无锁算法和非阻塞机制

原子变量锁使用起来比较方法,但是它存在一些问题:性能问题。尽管现代JVM对于锁进行了很多优化,但是在多线程下,线程上下文切换仍需要os的支持,这部分开销始终是无法避免的。在计算任务比较断的时候,线程上下文切换将占据极大的部分,发生激烈的竞争,影响性能。换句话来说,锁太重了。活跃性问题。一个线程失败,可能引起所有线程阻塞。volatile显然是一种非常轻量的同步操作,它不会引起上下文切换,但它无法支持复合操作,例如i++,看起来是一条指令,实际上是三条字节码指令。所以它也无法支持“测试并更新”这种

2022-03-31 10:09:52 806

原创 并发程序的测试

并发的测试并不容易,原因在于并发的不确定性——并发场景下,很多问题无法重现,甚至它还有一个专有的名词,“海森堡错误”。此外,对于Java来说,性能测试经常是比较困难的,这是由于JVM做了太多事,犹如一个黑箱,像垃圾回收,实时编译,提前编译等,对于性能的影响其实很大,要命的事,它们通常不是程序可控的范围,所以需要更加小心。正确性测试正确性测试有一部分是串行正确性——即,在串行环境下,我们通常考虑的该程序的种种不变性条件。例如初始容量,各种操作等等。这部分就不展开了,也没有什么特殊的。阻塞测试阻塞是并行

2022-03-27 18:58:02 4022

原创 避免活跃性问题

活跃性问题和安全性问题很接近,安全性问题会导致活跃性问题的出现,例如死锁。但活跃性问题还包括更多,例如饥饿(优先级出问题),响应慢,活锁等。大致就是程序活跃性上出现异常。死锁在os中,我们知道了死锁四个必要条件,以及如何从这四个条件进行预防——破坏必要条件其中之一。互斥。——资源一般都是互斥,这没办法改变。不可抢占。——支持中断的抢占式系统。环路等待。——资源编号,申请资源只能按序号升序,防止出现环路。占有与等待。——一次性分配所有资源。这里相当于从Java编程的角度队这个问题进行另一个角

2022-02-23 20:45:03 209

原创 Java线程池进阶

线程池是Executor框架的经典实现。本篇应该结合线程池原理解析来看。线程池的隐性耦合Executor将任务的提交和执行解耦,实际上就像大多数复杂的解耦过程一样,这种论断有些言过其实任务与执行策略之间,实际上存在一些隐形耦合,需要我们了解,才能在使用的过程避开。任务依赖任务之间最好独立存在,这有利于一致性和并发性。但现实是,这种依赖在少数情况下仍然存在,例如在任务中可能需要提交新的任务,这时候就可能引起长时间延迟、死锁等。任务影响了任务的执行策略。例如单线程池如果执行某个任务,这个任务又

2022-01-11 21:32:41 279

原创 如何正确地取消Java任务或服务?

引言取消正在执行的任务、线程、服务,并不是那么容易。对于某个任务而言,为了支持取消操作,你不得不增加取消的代码,而且不一定支持阻塞;对于服务而言更是如此,你不清楚服务内部是依赖什么实现,所以就无法正常取消。(例如,内部可能是阻塞队列,可能是多个Task)任务取消取消一个任务,或一段程序,最容易想到的操作是增加判断标志,每次执行的时候判断,否则退出程序。但自定义的变量并不能解决阻塞问题。例如下面代码,如果在循环中阻塞了,那么它永远无法判断取消标志。while(!cancelled) { do som

2022-01-07 20:48:42 1555

原创 VarHandle,可变句柄解析

JDK 9中新增的库,是java.util.concurrent.atomic和sun.misc.Unsafe操作的等价替代。VarHandle是通用的对象的域的引用句柄,提供原子的操作方法。直接看用法即可。// 对象域private volatile int state;private volatile Thread runner;private volatile WaitNode waiters;// 通用句柄private static final VarHandle STATE;pr

2022-01-03 12:40:32 487

原创 ScheduledExecutor和DelayQueue,Java任务延迟执行的秘密

引言Timer类的解析中提到,Timer类的缺陷:单线程Timer只有一个任务执行线程,如果某个TimerTask耗时较久,影响其他任务Timer不会捕获执行TimerTask时所抛出的异常,由于Timer是单线程,所以一旦出现异常,则线程就会终止,其他任务也得不到执行。系统时间敏感性,由于Timer中使用了currentTimeMillis做参考,所以系统时间变化会使得任务发生变化所以在JDK1.5后大家就抛弃了Timer,一般使用ScheduledThreadPoolExecutor。

2022-01-02 16:46:32 966

原创 FutureTask原理解析

引言我们都知道Runable接口,它非常简单。但是它有一个问题——无法获取执行结果,以及一旦可以获取执行结果,什么时候可以获取执行结果?public interface Runnable { public abstract void run();}FutureTask就是为了解决这个问题的,将Runnable包装为FutureTask之后,就可以get获取任务执行结果,如果任务没有执行完,那么当前线程就会阻塞。FutureTask确实非常好用,但我一直以来都比较好奇,将Runnable包

2022-01-02 11:09:58 955

原创 Timer类原理解析,任务延迟执行

APITimer类用于延迟任务的执行。schedule(TimerTask task, **long **delay),指定延迟时间schedule(TimerTask task, Date time),指定时间schedule(TimerTask task, **long **delay, **long **period),指定延迟时间和重复周期schedule(TimerTask task, Date firstTime, **long **period),指定初始时间和重复周期源码解读

2022-01-02 11:08:07 1239

原创 关于设计线程安全的类你所要知道的一切

设计线程安全的类设计安全的类的过程,需要包含三个要素:找出构成对象状态的所有变量找出状态变量的约束建立对象状态的并发访问策略​这三条也是本篇文章的核心,以下将会逐一展开对象状态和约束都是什么,以及重点,如何结合三条要素,去设计并发访问策略。有三种常用的模式,封闭实例,委托,拓展。状态和约束状态就是对象中的状态变量,约束则是涉及到并发不可变性的种种约束。之所以放在一起讲,是因为本身约束就是作用于变量上。找到状态和约束的过程,实际上也是收集同步需求的过程。状态对象的所有域都可能是状态

2021-12-20 21:09:08 290

原创 关于并发线程安全性你所需要知道的一切

如何保证线程安全?确保线程安全性,安全地在线程中共享对象是并发编程的基础,同时,这些概念其实可以推广到分布式环境下的安全性的考量,为了方便起见,后续假设是多线程的前提,但这些只是都可以很容易推广到多进程/多节点的环境。事实上,在已有大型程序上去分析并解决并发安全问题是非常困难的,幸运的是,面向对象编程思想除了提供结构优雅、可维护性高的类之外,更可能编写处线程安全的类(何为线程安全的类,后文会展开说明)。本质上,线程安全问题是由于类或对象中的状态变量,没有在多线程中进行正确的同步,有三种方式可以解决:

2021-12-19 11:24:28 338

原创 深入理解Java类加载机制,以及破坏双亲委派模型的实现方式

关于类加载器类加载器的使用//隐式加载User user=new User();//显式加载,并初始化Class clazz=Class.forName("com.test.java.User");//显式加载,但不初始化ClassLoader.getSystemClassLoader().loadClass("com.test.java.Parent了解类加载器的必要性开发人员大多数时候并不需要显示地使用类加载器,但了解整个机制对于了解类本身却很有用。遇到java.lang.Cla

2021-12-05 21:01:53 528

原创 Java进阶必备——学会阅读字节码

目标,学会阅读字节码!事实上整个执行过程都是操作数栈和局部变量表的交互过程。加载和存储指令加载到操作数栈中,为了效率,应对不同长度的需要,设计了不同长度的指令。类型常数指令范围int(boolean,byte,char,short)iconst[-1, 5]bipush[-128, 127]sipush[-32768, 32767]ldcany int valuelonglconst0, 1ldcany long valu

2021-12-02 15:14:51 385

原创 如何更好地编写Java方法

49. 检查参数的有效性编写方法和构造器的时候,要考虑参数的限制,把限制通过文档注明,并通过显示的方式来检查这些限制。否则,后果是什么明白为什么不好有时候比怎么做才好更重要。不检查参数的问题在于:方法可能在处理过程中失败,产生令人费解的结果。当然这是最显而易见的问题。更糟糕的是,方法返回了,但是结果是错误的。更糟糕的是,方法返回了正确结果,但是未来在某个时候,突然给你一个惊喜,而你完全找不到问题出在什么地方。这破坏了所谓的失败原子性(failure atomicity)最佳实践对于共有

2021-11-29 21:31:27 375

原创 垃圾回收器

背景知识指标与权衡吞吐量和暂停时间(垃圾收集时间,STW)是最重要的两个指标。从吞吐量公式来看,垃圾收集时间和吞吐量是互相权衡的。吞吐量=运行用户代码时间(运行用户代码时间+垃圾收集时间)吞吐量 = \frac{运行用户代码时间}{(运行用户代码时间+垃圾收集时间)}吞吐量=(运行用户代码时间+垃圾收集时间)运行用户代码时间​对于交互式要求高的应用来说,例如客户端,一般要求高响应,即每次尽可能短的垃圾收集时间。对于高性能需求的应用来说,例如服务端,一般强调高吞吐里。垃圾收集器发展历史了解一下技

2021-11-25 18:02:52 330

原创 垃圾回收相关技术

垃圾收集的三大假设这是三个统计上的经验法则。弱分代假说,绝大多数对象都是朝生夕灭。强分代假说,熬过越多次GC过程的对象就越难以消亡跨代引用假说,跨代引用只占少数。这一条实际上是前两条的推论,因为大多数对象都是同生共死的,所以一般都会位于通过区域。这也是后期实现各种分代/分区收集算法的基础——正因为少数,所以开销不至于太大。垃圾回收算法回顾经典算法从缺点演进方面来梳理一下三种算法。标记清楚算法的缺点在于内存碎片,空闲列表的维护使得整体的效率处于中等。复制算法解决了该问题,复制算法在存活对

2021-11-25 17:59:20 404

原创 Lambda和Stream

42. Lambda优先于匿名类主要是非常简洁,也为函数式编程提供了一定的支持。在大部分情况下,Lambda代替匿名类还是比较舒服的,正因为如此,需要了解lambda的边界。一行最为理想,三行以上就不要用lambda了lambda只支持函数式接口,匿名类可以支持抽象类的匿名实例的创建lambda不能获得自身的引用,this指向外围类,匿名类可以lambda和匿名类都无法实现方便的序列化、反序列化,需要使用私有静态嵌套类代替​演示一种比特定于常量的方法更简洁清晰的lambda实现。// E

2021-11-17 10:31:25 378

原创 Java Stream 底层原理

Stream API你可能没意识到Java对函数式编程的重视程度,看看Java 8加入函数式编程扩充多少功能就清楚了。Java 8之所以费这么大功夫引入函数式编程,原因有二:代码简洁函数式编程写出的代码简洁且意图明确,使用_stream_接口让你从此告别_for_循环。多核友好,Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下parallel()方法。​对_stream_的操作分为为两类,中间操作(intermediate operations)和结束操作(ter

2021-11-13 19:12:16 4364 1

原创 Java 泛型的原理以及泛型的补偿

繁琐的语法和泛型擦除原理Java泛型的语法有很多看起来毫无意义的规则和写法,例如:<? extends Fruit><T extends Fruit>(T[])new Object[size]// ...这些本质上都是由于Java泛型机制的实现原理——擦除。所谓的擦除:所有的泛型在编译之后都会被擦除,替换为它们的非泛型上界,例如List,其实实际的类型是ObjectJava的泛型指在编译之前多了额外的检查这看起来以一种很轻量优雅的方式实现的泛型,但实际上

2021-11-03 19:22:11 323 1

原创 泛型 -核心使用原则和原理

26. 不要使用原生类型Java的泛型比较受限。所有的泛型标记,都会在编译之后被完全擦除,变成其上界的类(很多时候是Object),而且Java的泛型也不是强制的,所以我们会情不自禁地想,为何不直接使用List?它不就等于List吗?答案是否定的。我们期望程序的错误尽可能在编译而不是在运行时发出警告。泛型,正好提供了很多这样的安全限制,它将很多错误从运行时移动到编译时,防止我们的程序在某天给我们惊喜。这我们非常好理解,如果使用了原生态类型,就是去了泛型在安全性和描述性方面的所有优势。List

2021-11-03 19:20:33 134

原创 类和接口相关

15. 使类可访问性最小化尽可能降低程序元素的可访问性,尤其注意引用可变对象,尽量降低可访问性(尽管有时不容易),以保证线程安全性。可变元素引用公有化合理方式是:// 维护一个不可变长的备份private static final Thing[] PRIVATE_VALUES = { ... };public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VAL

2021-10-25 10:36:51 80

原创 Java 内部类

Java内部类包括非静态内部类,局部内部类,匿名内部类,静态内部类四种。前三种非常类似,它们都叫内部类,它们持有对外部对象的引用,最后一种也称为嵌套类,它和外部类没有联系,它更像仅仅写在类内部的正常类。内部类是一种完善Java单继承机制从而取代多继承机制的产物,通过内部类可以进行灵活的继承而不影响外部类。所以它实际上有很多限制,需要用特殊的语法来进行保证,尽管这些语法可能看起来非常奇怪和不自然。幸运的是,日常对于这些边缘语法使用的也非常少。四种内部类非静态内部类由于内部类实际上比较相似,所以这边将会

2021-10-25 10:00:18 171

原创 对于所有对象都通用的方法

10. 覆盖equals时请遵守通用约定equals非常重要,它不像看起来那么简单,它非常重要用John Donne的话说,没有哪个类是鼓励的。一个类的实例通常会被频繁地传递给另一个类的实例。有许多类,包括集合类在内,都依赖于传递给它们的对象是否遵守equals约定。关键在于,一旦违背了某些通用约定,即使它们非强制性的,正因为它们非强制性的,一旦出现问题,非常难以发现。要实现高质量的equals覆盖,通常需要考虑更多,所以书中建议不要轻易覆盖equals,除非万不得已。一般情况下Object类的

2021-10-18 14:04:11 110

原创 创建和销毁对象

1. 用静态工厂代替构造器总结:优点主要源于静态工厂的灵活性,它有名称,可以返回灵活的类型,包括子类,隐藏类,可拓展类。为了可读性,最佳实践是遵守命名约定from,of,valueOf,instance,getInstance,crate,newInstance,getType,newType优点:有名称。构造器的缺点,参数列表多,有顺序,容易错误使用不必创建新对象。例如享元模式,常量池设计等。可以返回隐藏类型。参考Collections的实现(Collection的伴生类,由于JDK .

2021-10-13 21:01:29 86

原创 SpringMVC系列文章 入门、进阶、源码解析

SpringMVC入门、进阶、源码解析目录springMVC_helloworld.md,运行起来!从servlet,xml,注解三种方式来编写helloword引入了springMVC前端控制器的概念springMVC_basic.md,基础知识详解了前端控制器的运行流程注解@RequestMapping的使用和参数;方法参数的传入传出深入理解RestFul设计风格springMVC_源码.md ,源码级别的学习,发现组件的源码都很类似,特别是视图解析、数据绑定、国际化、异常

2021-04-18 22:07:49 108

原创 springMVC和tomcat中请求拦截原理

web.xml都是继承tomcat中web.xmlDispatcherServlet配置/之后会拦截所有的请求,它和/*的区别是,/*优先级更高,/则优先级低。如何理解这个点。例如tomcat的xml中其实默认配置了两个servlet。<!-- The mapping for the default servlet --><servlet-mapping> <servlet-name>default</servlet-name> &...

2021-04-18 21:52:34 759 2

原创 springMVC 几个进阶功能

视图与视图解析器视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。常用的视图类。常用的视图解析器。每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。实例一,JstlView视图与国际化springmvc-servlet.xml配置文件中配置解析器。一个是指定jstlView视图类。 一个是指定管理器,将国际化交予springMVC进行管理。 需..

2021-04-18 21:49:34 286 2

原创 springMVC 源码级别学习

DispatcherServlet核心逻辑DispatcherServlet处理逻辑如下。获得对应handler,即自定义的controller 获得对应的handler adapter 适配器调用用户自定义方法,返回model和view 处理和显示视图 跳转页面protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { H...

2021-04-18 21:48:12 88

原创 springMVC 基础知识

运行流程在springMVC中所有请求都会委托给DispatcherServlet进行处理,它需要完成以下任务。1)、客户端点击链接会发送 http://localhost:8080/hello 请求2)、来到tomcat服务器;3)、SpringMVC的前端控制器收到所有请求;4)、来看请求地址和@RequestMapping标注的哪个匹配,来找到到底使用那个类的哪个方法来处理5)、前端控制器找到了目标处理器类和目标方法,直接利用返回执行目标方法;6)、方法执行完成以后会有一个.

2021-04-18 21:46:26 106

原创 SpringMVC HelloWorld

概述从servlet到注解的hello world演进过程,了解这个过程主要因为原始的方法更加好理解原理。Servlet HelloWorld在项目src/main/java中实现一个servlet,我们可以看到,请求被xml中映射分析,发送到以下servlet中,然后在这里做业务处理,最后将返回结果,交给jsp视图去显示。//实现Servlet接口public class HelloServlet extends HttpServlet { @Override ...

2021-04-18 21:44:56 1743

原创 动态规划,博弈石头游戏系列

博弈游戏石头游戏由两人分别取石头,假定二人每次都是最优策略,在一定的规则下,求最终结果的一类题目。这类题目体现了动态规划的特点:本质上是暴力求解所有子问题,但是不重复需要良好的dp定义,保证子问题不重叠框架这是一种通用的博弈游戏的套路。虽然效率比较低。 int[][][] memo; int[] dp(int i, int j, int[] piles) { if (j <= i) return memo[i][j]; if (memo

2021-02-21 08:34:53 394

原创 动态规划,买股票系列

买股票系列有限状态机。一种区别与序列dp定义的动态规划定义方法。通用框架int n = prices.length, K = k;int memo[][][] = new int[n + 1][K + 1][2];for (int i = 0; i <= n; i++) memo[i][0][1] = Integer.MIN_VALUE;for (int i = 0; i <= K; i++) memo[0][i][1] = Integer.MIN_VALUE;for (int

2021-02-21 08:34:06 182

原创 887高楼扔鸡蛋

877 高楼抛鸡蛋问题这是一道经典的题目。有多种解决方法,而且题目本身非常抽象,即使case很少也不好理解。例如你基本上很难想明白2个鸡蛋6层楼,需要扔多少次。这个问题是有最优解的,即对于任意k个鸡蛋,n层,必定存在一种最优方案,使得测试次数达到最少,该方案可以规定每个测试的测试点(解法二可以更好体现这一点)。这个问题有很多种解,部分解非常精巧但是意义并不是很大。解法一,动态规划,非常直观的一种解法,也非常重要。其中很有意思的就是二分搜索的优化,以及对于max,min的复合优化目标的分析——使用图

2021-02-16 19:32:10 178

原创 92翻转链表

92. Reverse Linked List II翻转链表。https://leetcode.com/problems/reverse-linked-list-ii/思路很简单,难点在于实现细节。v1迭代实现前后指针,遍历翻转,难点是细节控制。为了一致性,在头部添加了哨兵节点,减少了很多判断。复杂度时间复杂度显然为O(m),一次遍历解决问题。空间消耗为O(1)public class Solution { public ListNode reverseBetween(ListNo

2021-02-07 08:16:10 91

原创 295寻找流的中位数

1. 问题分析Find Median from Data Stream维护流数据的中值https://leetcode.com/problems/find-median-from-data-stream/中值问题,原本的中值问题,由于只需要局部有序,即使满足mid前面都小于mid,mid后都大于mid即可,因此可以采用递归partition的方法来得到O(log N)的解法。但本问题是流问题,数据实时读入,实时找中值。问题的核心是:有序性,这样才能方便地找中值例如有序数组

2021-02-07 08:15:07 129

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除