- public Data end() {
- return new Data(end.getTime());
- }
- //带两个参数,避免没有传参导致的问题
- static init min(int firstArg, int... remainingArgs) {
- int min = firstArg;
- for(int arg : remainingArgs) {
- ...
- }
- }
- //错误
- Math.abs(new Random().nextInt());
- //正确
- Random.nextInt(int)
float 和 double 类型尤其不适合用于货币计算,因为要让一个 float 或 double 精确地表示 0.1(或者 10 的 ren'he'qi'ta 任何其他负数次方值)是不可能的。
使用 BigDecimal 代替 double:
BigDecimal 允许你完全控制舍入,每当一个操作设计舍入的时候,它允许你从 8 种舍入模式中选择其一。但是缺点是与基本运算类型比,不仅不方便,而且很慢。如果性能非常关键,并且又不介意自己记录是金子小数点,而且涉及的数值又不太大,就可以使用 int 或 long(例如 0.1 改变单位计作 10)。如果数值范围没超过 9 位十进制数字,就可以使用 int。如果不超过 18 位数值,就可以使用 long。如果数值超过 18 位数字,就必须使用 BigDecimal。
当程序装箱了基本类型值时,会导致高开销和不必要的对象创建。
连接操作符不适合运用在大规模的场景中,为连接 n 个字符串而重复地使用字符串连接操作符,需要 n 的平方级的时间。这是由于字符串不可变,当两个字符串被连接在一起时,它们的内容都要被拷贝。
使用 StringBuilder:
如果有合适的接口类型存在,那么对于参数、返回值、变量和域来说,就都应该使用接口类型进行声明。只有当你利用构造器创建某个对象的时候,才真正需要引用这个对象的类。
这样会使程序更灵活,当你决定更换实现时,只需要改变构造器中类的名称:
所有的代码都可以继续工作,代码并不知道原来的实现类型,所以对于这种变化并不在意。
反射机制允许一个类使用另一个类,即使当前者被编译的时候后者还根本不存在,然而这种能力也是要付出代价的:
不要优先使用基于异常的模式:
一般而言,失败的方法调用应该使对象保持在被调用之前的状态。具有这种属性的方法被称为具有失败原子性(failure atomic)。有几种途径可以实现这种效果:
忽略一个异常非常容易,只需将方法调用通过 try 语句包围起来,并包含一个空的 catch 块。空的 catch 块会使异常达不到应有的目的,至少,catch 块也应该包含一条说明,解释为什么可以忽略这个异常。
正确地使用同步可以保证没有任何方法会看到对象处于不一致的状态中。它还可以保证刚进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护的之前所有的修改效果。换句话说,读取一个非 long 或 double 类型的变量,可以保证返回的值是某个线程保存在该变量中的,即使多个线程在没有同步的情况下并发地修改这个变量也是如此。
不要使用 Thread.stop 方法。要阻止一个线程妨碍另一个线程,建议做法是让第一个线程轮训一个 boolean 域,这个域一开始为 false,但是可以通过第二个线程设置为 true,以表示第一个线程将终止自己。由于 boolean 域的读写操作都是原子的,程序员在访问这个域的时候不再使用同步。
实际上,如果读和写操作没有都被同步,同步就不会起作用。
如果变量修饰符是 volatile,则读取变量时不需要锁,虽然 volatile 修饰符不执行互斥访问,但它可以保证任何一个线程在读取该域的时候都将看到最近刚刚被写入的值。
使用 volatile 的时候务必要小心。
虽然 number 是原子的,但是增量操作符不是原子的,它首先读取值,然后写回一个新值。如果第二个线程在第一个线程读取旧值和返回新值期间读取这个域就会出错。
在一个被同步的区域内部,不要调用设计成要被覆盖的方法,或者是由客户端以函数对象的形式提供的方法。这样的方法是外来的,这个类不知道方法会做什么事情,也无法控制它,从同步区域中调用它很可能会导致异常、死锁或者数据损坏。
通常,你应该在同步区域内做尽可能少的工作。如果你必须要执行某个很耗时的动作,应该设法把这个动作移到同步区域的外面。
Java1.5 增加了 java.util.concurrent,这个包中包含了一个 Executor Framework:
你可以利用 executor service 完成更多的事情。例如,可以等待一个任务集合中的任何任务或所有任务完成(invokeAny 或 invokeAll),你可以等待 executor service 优雅地完成终止(awaitTermination),可以在任务完成时逐个地获取这些任务的结果(ExecutorCompletionService)等。
自从 java1.5 发型版本开始,java 就提供了更高级的并发工具,他们可以完成以前必须在 wait 和 notify 上手写代码来完成的各项工作。其分成三类:
同步器(Synchronizer)是一些使线程能够等待另一个线程的对象,允许他们协调动作。最常用的同步器是 CountDownLatch 和 Semaphore。
倒计数锁存器(CountDown Latch)是一次性的障碍,允许一个或者多个线程等待一个或者多个其他线程来做某些事情。CountDownLatch 是唯一构造器带有一个 int 类型的参数,这个 int 参数是指允许所有在等待的线程被处理之前,必须在锁存器上调用 countDown 方法的次数。
例如:一个方法带有一个执行该动作的 executor,一个并发级别(表示要并发执行该动作的次数),以及表示该动作的 runnable。所有的工作线程自身都准备好,要在 time 线程启动时钟之前运行该动作(为了实现准确的定时)。当最后一个工作线程准备好运行该动作时,timer 线程就 "发起头炮",同事允许工作线程执行该动作,一旦最后一个工作线程执行完该动作,timer 线程就立即停止计时。直接在 wait 和 notify 上实现这个逻辑至少来说会很混乱,而在 CountDownLatch 之上实现则相当简单:
用 ready 来告诉 timer 线程他们已经准备好了。然后工作线程会在 start 上等待。当最后一个工作线程调用 ready.countDown 时,timer 线程记录下起始时间,并调用 start.countDown,允许所有的工作线程继续进行。然后 timer 线程在 done 上等待,直到最后一个工作线程运行完该动作,并调用 donw.countDown。一旦调用这个,timer 线程就会苏醒过来,并记录下结束时间。
wait 方法的标准模式:
始终应该使用 wait 循环模式来调用 wait 方法;永远不要在循环之外调用 wait 方法。循环会在等待之前和之后测试条件。
线程安全性的几种级别。(这份列表并没有涵盖所有的可能,而只是些常见的情形:
私有锁对象模式只能用在无条件的线程安全类上。有条件的线程安全类不能使用这种模式,因为它们必须在文档中说明:在执行某些方法调用序列时,它们的客户端程序必须获得哪把锁。
私有锁对象模式特别适用于那些专门为继承而设计的类。如果这种类使用它的实例作为锁对象,之类可能很容易在无意中妨碍基类的操作,反之亦然,出于不同的目的而使用相同的锁,子类和基类很可能会 "互相绊住对方的脚"。
有条件的线程安全类必须在文档中指明哪些方法调用序列需要外部同步,以及在执行这些序列的时候需要获得哪把锁。如果你编写的是无条件的线程安全类,就应该考虑使用私有锁对象来代替同步的方法以防止客户端程序和子类的不同步干扰。
如果处于性能的考虑需要对静态域使用延迟初始化:
如果处于性能的考虑需要对实例域使用延迟初始化:
如果需要延迟初始化一个可以接受重复初始化的实例域:
线程不应该一直处于忙 - 等状态,即反复地检查一个共享对象,以等待某些事情的发生。
不要让应用程序的正确性依赖于线程调度器,否则结果得到的应用程序将既不健壮,也不具有可移植性。不要依赖 Thread.yield 或者线程优先级。线程优先级可以用来提高一个已经能够正常工作的程序的服务质量,但永远不应该用来 "修正" 一个原本能不能工作的程序。
实现 Serializable 接口而付出的巨大代价是,一旦一个类被发布,就大大降低了 "改变这个类的实现" 的灵活性。 如果一个类实现了 Serializable 接口,它的字节流编码(序列化形式)就变成了它的导出的 API 的一部分,一旦这个类被广泛使用,往往必须永远支持这种序列化形式。
第二个代价是,它增加了出现 bug 和安全漏洞的可能性。你可能会忘记确保:反序列化过程必须也要保证所有 "由真正的构造器建立起来的约束关系",并且不允许攻击者访问正在构造过程中的对象的内部信息。
第三个代价是,随着类发行新的版本,相关的测试负担也增加了。可序列化的类被修订后,你必须既要确保 "序列化 - 反序列化" 过程成功,也要确保结果产生的对象真正是原始对象的复制品。
内部类不应该实现 Serializable。
如果一个类为了继承而设计,要更加小心。对于这样的类而言,在 "允许子类实现 Serializable 接口" 或者 "禁止子类实现 serialzable" 两者间的一个折衷方案是:提供一个可访问的无参构造器,这种方案允许(但不要求)子类实现 Serializable 接口。
来源: https://juejin.im/post/5a369179f265da43176a3957