Effective java 系列之避免过度同步和不要使用原生态类型,优先考虑泛型
避免过度同步(67):在一个被同步的方法或代码块中,不要调用哪些被设计成被覆盖的方法或者是由客户端以函数对象的形式提供的方法(21)。
有点拗口,书上提供的创建者与观察者模式,add方法太多,看得眼花缭乱,重新写了一个例子:
package com.example.demo.effective;
public interface Believer {
void confide();
}
package com.example.demo.effective; import com.google.common.collect.Lists; import java.util.List; /**
* 上帝
*/
public class God {
/**
* 天国
*/
private List<Believer> believers = Lists.newArrayList(); public void addBeliever(Believer be){
synchronized (believers){
believers.add(be);
}
} public void removeBeliever(Believer be){
synchronized (believers){
believers.remove(be);
}
} public void getBeliever(Believer be){
synchronized (believers){
//选一个大主教
System.out.println(believers.get(0));
}
} /**
* 倾听每位信徒倾述
*/
public void listenEveryBeliever(){
synchronized (believers){
for(Believer be : believers){
be.confide();
}
}
} }
测试:
@Test
public void test1(){
God god = new God();
god.addBeliever(new Believer() {
@Override
public void confide() {
System.out.println("I love my son....");
}
});
god.listenEveryBeliever();
}
I love my son....
没问题,再看下面:
@Test
public void test2(){
God god = new God(); god.addBeliever(new Believer() {
@Override
public void confide() {
System.out.println("I love my son....");
}
}); //现在出现一个亵神者,放弃信仰了
god.addBeliever(new Believer() {
@Override
public void confide() {
god.removeBeliever(this);
}
});
god.listenEveryBeliever();
}
结果,在上帝做倾听信徒时,居然出现了渎神者,大家都知道,集合在循环时,时不可以增减元素的。

在继续看,死锁了....
@Test
public void test3(){
God god = new God(); god.addBeliever(new Believer() {
@Override
public void confide() {
System.out.println("I love my son....");
}
}); //现在出现一个亵神者,放弃信仰了
god.addBeliever(new Believer() {
@Override
public void confide() {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(()->{god.getBeliever(this);}).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally {
executor.shutdown();
}
}
});
god.listenEveryBeliever();
}
这里死锁,分析下:god.listenEveryBeliever(),主线程锁住天堂,上帝开始倾听信徒倾述,但此时有一个信徒倾述时另启一个线程,并在此等待主线程执行结束,当然永远也等不到....
所以正确的姿势:原则:不要在同步块中,调用可能被覆盖的方法
/**
* 倾听每位信徒倾述
*/
public void listenEveryBeliever(){ List<Believer> believersBat = null;
synchronized (believers){
//快照副本
believersBat = Lists.newArrayList(believers);
}
for(Believer be : believersBat){
be.confide();
}
}
请不要在新代码中使用原生态类型(23)
jdk1.5版本增加了泛型,如果还是再用低于1.5的jdk,不说了。
泛型的好处:1、表述性 2、安全性(主要体现在编译阶段的泛型检查,有些错误不必要等到运行时才发现)
@Test
public void test1(){
//运行时才发现类型异常,追悔吧...
List list = Lists.newArrayList("adc");
getFirstEle1(list);//java.lang.String cannot be cast to java.lang.Integer
} @Test
public void test2(){
List list = Lists.newArrayList("adc");
getFirstEle2(list);//adc
} @Test
public void test3(){
//结合test2() List和List<Object>主要区别:
//1、List 时原生态类型,逃避了类型检查。List<Object>则明确告知编译器
//2、List<String> 时List的字类,而不是List<Object>子类
List<String> list = Lists.newArrayList("adc");
//getFirstEle2(list);//编译报错
} @Test
public void test4(){
List<String> list = Lists.newArrayList("adc");
getFirstEle3(list);//adc
} @Test
public void test5(){
List<? extends String> list1 = Lists.newArrayList("adc");
List<String> list2 = Lists.newArrayList("ap"); //<? extends E> 是 Upper Bound(上限) 的通配符,用来限制元素的类型的上限
//list2 元素类型String,list1元素类型继承String,大类型->小类型,报错
//list1.addAll(list2);
list2.addAll(list1);
System.out.println(list2); //[ap, adc]
} @Test
public void test6(){
// <? super E> 是 Lower Bound(下限) 的通配符 ,用来限制元素的类型下限
List<? super String> list1 = Lists.newArrayList("adc");
List<String> list2 = Lists.newArrayList("ap");
list1.addAll(list2);
System.out.println(list1); //[ap, adc]
} /**
* List 原生态类型
* @param list
*/
public static void getFirstEle1(List list){
int i = (int) list.get(0);
System.out.println(i);
} /**
* List<Object> 从表述上,时所有Object元素都ok
* @param list
*/
public static void getFirstEle2(List<Object> list){
Object i = (Object) list.get(0);
System.out.println(i);
} /**
* <?> 可接受任意泛型,多定义在变量中
* @param list
*/
public static void getFirstEle3(List<?> list){
System.out.println(list.get(0));
} /**
* <T> 表示方法要用到泛型参数,多用在类和方法上
* @param list
* @param <T>
*/
public static <T> void getFirstEle4(List<T> list){
T t = list.get(0);
System.out.println(t);
}
私有构造器强化不可实例化
使用场景:通常用在工具类,因为他们都不希望被实例化。
public class MyUtils {
private MyUtils(){
//不管外部还是内部,该类实例化就会抛异常
throw new AssertionError();
}
public static String method(){
return "";
}
}
枚举类型:
通常程序中需要用到大量的常量,优雅的使用枚举将对代码可读性、健壮性、维护性有显著效果
enum代替int常量,用实例域代替序数
package com.example.demo.effective.enumDemo;
public enum StatusEnum {
APPLY(1),ACTIVE(2),FREEZE(3),FREE(4);
private final int index;
StatusEnum(int size){
this.index = size;
}
public void method(){
//System.out.println(this.ordinal()); 位置顺序变动,会乱套
System.out.println(index);
}
}
用EnumSet代替位域
// num << x,相当于num * 2^x,
//|或运算符:即两个二进制数同位中,只要有一个为1则结果为1,若两个都为1其结果也为1
public static final int STYLE_BOLD = 1 << 0;
public static final int STYLE_ITALIC = 1 << 1;
public static final int STYLE_UNDERLINE = 1 << 2;
public static final int STYLE_STRIKETHROUGH = 1 << 3;
@Test
public void test3(){
System.out.println(STYLE_UNDERLINE|STYLE_STRIKETHROUGH);//
} @Test
public void test4(){
//用EnumSet代替位域
//位域表示法允许利用位操作,有效地执行先 union(联合)和 intersection(交集)这样的集合操作 如:test3()
EnumSet<StatusEnum> status1 = EnumSet.of(StatusEnum.APPLY, StatusEnum.ACTIVE);
System.out.println(status1); //确定,EnumSet可变,用unmodifiableSet 封装
Set<StatusEnum> unmodifiableStyle = Collections.unmodifiableSet(status1);
unmodifiableStyle.add(StatusEnum.FREE); //运行时:UnsupportedOperationException
}
Effective java 系列之避免过度同步和不要使用原生态类型,优先考虑泛型的更多相关文章
- Effective Java 第三版——78. 同步访问共享的可变数据
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- Effective java 系列之更优雅的关闭资源-try-with-resources
背景: 在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在 ...
- Effective java 系列之异常转译
异常转译:当位于最上层的子系统不需要关心底层的异常细节时,常见的作法时捕获原始异常,把它转换一个新的不同类型的异常,在将新异常抛出. 通常方法捕获底层异常,然后抛高层异常. public static ...
- Effective Java 第三版——89. 对于实例控制,枚举类型优于READRESOLVE
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- Effective Java 第三版——79. 避免过度同步
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- Effective.Java第78-90条(同步相关)
78. 同步访问共享的可变数据 为了在线程之间进行可靠的通信,也为了互斥访问,同步是必要的. 不共享可变的数据.要么共享不可变的数据,要么压根不共享.换句话说,将可变数据限制在单线程中. 当多个线程 ...
- Effective Java通俗理解(下)
Effective Java通俗理解(上) 第31条:用实例域代替序数 枚举类型有一个ordinal方法,它范围该常量的序数从0开始,不建议使用这个方法,因为这不能很好地对枚举进行维护,正确应该是利用 ...
- 《Effective Java(中文第二版)》【PDF】下载
<Effective Java(中文第二版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382186 Java(中文第二版)& ...
- Effective Java 第三版——48. 谨慎使用流并行
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- 解决*.props打开失败问题
由于不同机器的绝对地址不一样,可能会出现解决*.props打开失败问题,解决方向如下: 1.找到这里缺失的.props文件,复制到固定路径下: 2.强行打开代码,这个时候是报错的 3.选择编辑 4.将 ...
- RAC +MVVM
https://blog.csdn.net/capf_sam/article/details/60960530 https://blog.csdn.net/capf_Sam/article/detai ...
- topcoder srm 305 div1
problem1 link 直接按照题意模拟即可. import java.util.*; import java.math.*; import static java.lang.Math.*; pu ...
- 当模版引擎遇到点("."),会按照下列顺序查询:
字典查询,例如:foo["bar"] 属性或方法查询,例如:foo.bar 数字索引查询,例如:foo[bar]
- Tutorial on GoogleNet based image classification --- focus on Inception module and save/load models
Tutorial on GoogleNet based image classification 2018-06-26 15:50:29 本文旨在通过案例来学习 GoogleNet 及其 Incep ...
- 论文笔记:ReNet: A Recurrent Neural Network Based Alternative to Convolutional Networks
ReNet: A Recurrent Neural Network Based Alternative to Convolutional Networks2018-03-05 11:13:05 ...
- (zhuan) Paper Collection of Multi-Agent Reinforcement Learning (MARL)
this blog from: https://github.com/LantaoYu/MARL-Papers Paper Collection of Multi-Agent Reinforcemen ...
- SHOI 2017 相逢是问候(扩展欧拉定理+线段树)
题意 https://loj.ac/problem/2142 思路 一个数如果要作为指数,那么它不能直接对模数取模,这是常识: 诸如 \(c^{c^{c^{c..}}}\) 的函数递增飞快,不是高精度 ...
- Using git-flow to automate your git branching workflow
Using git-flow to automate your git branching workflow Vincent Driessen’s branching model is a git b ...
- 关于C++中的friend友元函数的总结
1.友元函数的简单介绍 1.1为什么要使用友元函数 在实现类之间数据共享时,减少系统开销,提高效率.如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数. ...