![](https://img-blog.csdnimg.cn/20201014180756918.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
books
文章平均质量分 91
KDLin
这个作者很懒,什么都没留下…
展开
-
Java序列化攻击和最佳实践
85. 其他序列化优于Java序列化Java序列化机制很危险,在新编写的系统中,没有理由再使用Java序列化,应该使用其他序列化机制,例如跨平台的JSON序列化;尤其不要反序列化任何不信任的数据,因为容易遭受序列化攻击。原因在于,反序列化不被信任的数据,容易受到序列化攻击,例如远程代码执行(RCE),拒绝服务(DoS)等等。研究人员可以基于Java序列化机制开发出很多巧妙的攻击片段。例如:public class BombSerializable { public static void原创 2022-04-29 09:36:47 · 485 阅读 · 0 评论 -
你真的懂得Java异常的正确使用姿势吗?
引言异常机制我们再熟悉不过,在开发环境中,它非常有用。它能帮我们的程序从错锁中恢复,也能在程序奔溃的时候方便我们定位异常原因。但大家在生产环境中会不会有这种感觉:这个异常究竟应该catch处理掉呢,还是应该抛给调用方?底层抛出来的异常,究竟在哪一层处理比较好?应该抛出什么异常?尽管我们会想,属于用户责任就应该抛给用户,但这里的边界,实际开发中很难界定。本文来回答这个问题,并且会给出异常机制相关的最佳实践。回忆一下异常的知识。其中:Error是严重的错误,例如内存耗尽,栈溢出等等,它属于非受检异原创 2022-04-03 15:12:41 · 354 阅读 · 0 评论 -
原子变量、无锁算法和非阻塞机制
原子变量锁使用起来比较方法,但是它存在一些问题:性能问题。尽管现代JVM对于锁进行了很多优化,但是在多线程下,线程上下文切换仍需要os的支持,这部分开销始终是无法避免的。在计算任务比较断的时候,线程上下文切换将占据极大的部分,发生激烈的竞争,影响性能。换句话来说,锁太重了。活跃性问题。一个线程失败,可能引起所有线程阻塞。volatile显然是一种非常轻量的同步操作,它不会引起上下文切换,但它无法支持复合操作,例如i++,看起来是一条指令,实际上是三条字节码指令。所以它也无法支持“测试并更新”这种原创 2022-03-31 10:09:52 · 836 阅读 · 0 评论 -
并发程序的测试
并发的测试并不容易,原因在于并发的不确定性——并发场景下,很多问题无法重现,甚至它还有一个专有的名词,“海森堡错误”。此外,对于Java来说,性能测试经常是比较困难的,这是由于JVM做了太多事,犹如一个黑箱,像垃圾回收,实时编译,提前编译等,对于性能的影响其实很大,要命的事,它们通常不是程序可控的范围,所以需要更加小心。正确性测试正确性测试有一部分是串行正确性——即,在串行环境下,我们通常考虑的该程序的种种不变性条件。例如初始容量,各种操作等等。这部分就不展开了,也没有什么特殊的。阻塞测试阻塞是并行原创 2022-03-27 18:58:02 · 4623 阅读 · 0 评论 -
避免活跃性问题
活跃性问题和安全性问题很接近,安全性问题会导致活跃性问题的出现,例如死锁。但活跃性问题还包括更多,例如饥饿(优先级出问题),响应慢,活锁等。大致就是程序活跃性上出现异常。死锁在os中,我们知道了死锁四个必要条件,以及如何从这四个条件进行预防——破坏必要条件其中之一。互斥。——资源一般都是互斥,这没办法改变。不可抢占。——支持中断的抢占式系统。环路等待。——资源编号,申请资源只能按序号升序,防止出现环路。占有与等待。——一次性分配所有资源。这里相当于从Java编程的角度队这个问题进行另一个角原创 2022-02-23 20:45:03 · 215 阅读 · 0 评论 -
Java线程池进阶
线程池是Executor框架的经典实现。本篇应该结合线程池原理解析来看。线程池的隐性耦合Executor将任务的提交和执行解耦,实际上就像大多数复杂的解耦过程一样,这种论断有些言过其实任务与执行策略之间,实际上存在一些隐形耦合,需要我们了解,才能在使用的过程避开。任务依赖任务之间最好独立存在,这有利于一致性和并发性。但现实是,这种依赖在少数情况下仍然存在,例如在任务中可能需要提交新的任务,这时候就可能引起长时间延迟、死锁等。任务影响了任务的执行策略。例如单线程池如果执行某个任务,这个任务又原创 2022-01-11 21:32:41 · 301 阅读 · 0 评论 -
如何正确地取消Java任务或服务?
引言取消正在执行的任务、线程、服务,并不是那么容易。对于某个任务而言,为了支持取消操作,你不得不增加取消的代码,而且不一定支持阻塞;对于服务而言更是如此,你不清楚服务内部是依赖什么实现,所以就无法正常取消。(例如,内部可能是阻塞队列,可能是多个Task)任务取消取消一个任务,或一段程序,最容易想到的操作是增加判断标志,每次执行的时候判断,否则退出程序。但自定义的变量并不能解决阻塞问题。例如下面代码,如果在循环中阻塞了,那么它永远无法判断取消标志。while(!cancelled) { do som原创 2022-01-07 20:48:42 · 1589 阅读 · 0 评论 -
关于设计线程安全的类你所要知道的一切
设计线程安全的类设计安全的类的过程,需要包含三个要素:找出构成对象状态的所有变量找出状态变量的约束建立对象状态的并发访问策略这三条也是本篇文章的核心,以下将会逐一展开对象状态和约束都是什么,以及重点,如何结合三条要素,去设计并发访问策略。有三种常用的模式,封闭实例,委托,拓展。状态和约束状态就是对象中的状态变量,约束则是涉及到并发不可变性的种种约束。之所以放在一起讲,是因为本身约束就是作用于变量上。找到状态和约束的过程,实际上也是收集同步需求的过程。状态对象的所有域都可能是状态原创 2021-12-20 21:09:08 · 299 阅读 · 0 评论 -
关于并发线程安全性你所需要知道的一切
如何保证线程安全?确保线程安全性,安全地在线程中共享对象是并发编程的基础,同时,这些概念其实可以推广到分布式环境下的安全性的考量,为了方便起见,后续假设是多线程的前提,但这些只是都可以很容易推广到多进程/多节点的环境。事实上,在已有大型程序上去分析并解决并发安全问题是非常困难的,幸运的是,面向对象编程思想除了提供结构优雅、可维护性高的类之外,更可能编写处线程安全的类(何为线程安全的类,后文会展开说明)。本质上,线程安全问题是由于类或对象中的状态变量,没有在多线程中进行正确的同步,有三种方式可以解决:原创 2021-12-19 11:24:28 · 352 阅读 · 0 评论 -
如何更好地编写Java方法
49. 检查参数的有效性编写方法和构造器的时候,要考虑参数的限制,把限制通过文档注明,并通过显示的方式来检查这些限制。否则,后果是什么明白为什么不好有时候比怎么做才好更重要。不检查参数的问题在于:方法可能在处理过程中失败,产生令人费解的结果。当然这是最显而易见的问题。更糟糕的是,方法返回了,但是结果是错误的。更糟糕的是,方法返回了正确结果,但是未来在某个时候,突然给你一个惊喜,而你完全找不到问题出在什么地方。这破坏了所谓的失败原子性(failure atomicity)最佳实践对于共有原创 2021-11-29 21:31:27 · 384 阅读 · 0 评论 -
Lambda和Stream
42. Lambda优先于匿名类主要是非常简洁,也为函数式编程提供了一定的支持。在大部分情况下,Lambda代替匿名类还是比较舒服的,正因为如此,需要了解lambda的边界。一行最为理想,三行以上就不要用lambda了lambda只支持函数式接口,匿名类可以支持抽象类的匿名实例的创建lambda不能获得自身的引用,this指向外围类,匿名类可以lambda和匿名类都无法实现方便的序列化、反序列化,需要使用私有静态嵌套类代替演示一种比特定于常量的方法更简洁清晰的lambda实现。// E原创 2021-11-17 10:31:25 · 385 阅读 · 0 评论 -
Java 泛型的原理以及泛型的补偿
繁琐的语法和泛型擦除原理Java泛型的语法有很多看起来毫无意义的规则和写法,例如:<? extends Fruit><T extends Fruit>(T[])new Object[size]// ...这些本质上都是由于Java泛型机制的实现原理——擦除。所谓的擦除:所有的泛型在编译之后都会被擦除,替换为它们的非泛型上界,例如List,其实实际的类型是ObjectJava的泛型指在编译之前多了额外的检查这看起来以一种很轻量优雅的方式实现的泛型,但实际上原创 2021-11-03 19:22:11 · 333 阅读 · 1 评论 -
泛型 -核心使用原则和原理
26. 不要使用原生类型Java的泛型比较受限。所有的泛型标记,都会在编译之后被完全擦除,变成其上界的类(很多时候是Object),而且Java的泛型也不是强制的,所以我们会情不自禁地想,为何不直接使用List?它不就等于List吗?答案是否定的。我们期望程序的错误尽可能在编译而不是在运行时发出警告。泛型,正好提供了很多这样的安全限制,它将很多错误从运行时移动到编译时,防止我们的程序在某天给我们惊喜。这我们非常好理解,如果使用了原生态类型,就是去了泛型在安全性和描述性方面的所有优势。List原创 2021-11-03 19:20:33 · 148 阅读 · 0 评论 -
类和接口相关
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 · 86 阅读 · 0 评论 -
Java 内部类
Java内部类包括非静态内部类,局部内部类,匿名内部类,静态内部类四种。前三种非常类似,它们都叫内部类,它们持有对外部对象的引用,最后一种也称为嵌套类,它和外部类没有联系,它更像仅仅写在类内部的正常类。内部类是一种完善Java单继承机制从而取代多继承机制的产物,通过内部类可以进行灵活的继承而不影响外部类。所以它实际上有很多限制,需要用特殊的语法来进行保证,尽管这些语法可能看起来非常奇怪和不自然。幸运的是,日常对于这些边缘语法使用的也非常少。四种内部类非静态内部类由于内部类实际上比较相似,所以这边将会原创 2021-10-25 10:00:18 · 176 阅读 · 0 评论 -
对于所有对象都通用的方法
10. 覆盖equals时请遵守通用约定equals非常重要,它不像看起来那么简单,它非常重要用John Donne的话说,没有哪个类是鼓励的。一个类的实例通常会被频繁地传递给另一个类的实例。有许多类,包括集合类在内,都依赖于传递给它们的对象是否遵守equals约定。关键在于,一旦违背了某些通用约定,即使它们非强制性的,正因为它们非强制性的,一旦出现问题,非常难以发现。要实现高质量的equals覆盖,通常需要考虑更多,所以书中建议不要轻易覆盖equals,除非万不得已。一般情况下Object类的原创 2021-10-18 14:04:11 · 118 阅读 · 0 评论 -
创建和销毁对象
1. 用静态工厂代替构造器总结:优点主要源于静态工厂的灵活性,它有名称,可以返回灵活的类型,包括子类,隐藏类,可拓展类。为了可读性,最佳实践是遵守命名约定from,of,valueOf,instance,getInstance,crate,newInstance,getType,newType优点:有名称。构造器的缺点,参数列表多,有顺序,容易错误使用不必创建新对象。例如享元模式,常量池设计等。可以返回隐藏类型。参考Collections的实现(Collection的伴生类,由于JDK .原创 2021-10-13 21:01:29 · 90 阅读 · 0 评论 -
创建和销毁对象
创建和销毁对象考虑使用静态方法代替构造器好处主要是两方面。灵活 ,每个静态方法都有自己的名字,这使得需要有大量类似参数的构造方法可以使用不同的名字加以区分。方法重载不足以解决需求,以及方法名可以使得不必每次都查看文档说明。实例受控 ,例如,单例或者内存池,对象初始化之后,不是直接返回,而可以对例如数量进行控制,我认为这才是要点。遇到多个构造其参数时考虑用Builder一般的解决方案是重...原创 2018-12-30 16:03:02 · 139 阅读 · 0 评论