避免过度同步(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 系列之避免过度同步和不要使用原生态类型,优先考虑泛型的更多相关文章

  1. Effective Java 第三版——78. 同步访问共享的可变数据

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  2. Effective java 系列之更优雅的关闭资源-try-with-resources

    背景: 在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在 ...

  3. Effective java 系列之异常转译

    异常转译:当位于最上层的子系统不需要关心底层的异常细节时,常见的作法时捕获原始异常,把它转换一个新的不同类型的异常,在将新异常抛出. 通常方法捕获底层异常,然后抛高层异常. public static ...

  4. Effective Java 第三版——89. 对于实例控制,枚举类型优于READRESOLVE

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  5. Effective Java 第三版——79. 避免过度同步

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  6. Effective.Java第78-90条(同步相关)

    78.  同步访问共享的可变数据 为了在线程之间进行可靠的通信,也为了互斥访问,同步是必要的. 不共享可变的数据.要么共享不可变的数据,要么压根不共享.换句话说,将可变数据限制在单线程中. 当多个线程 ...

  7. Effective Java通俗理解(下)

    Effective Java通俗理解(上) 第31条:用实例域代替序数 枚举类型有一个ordinal方法,它范围该常量的序数从0开始,不建议使用这个方法,因为这不能很好地对枚举进行维护,正确应该是利用 ...

  8. 《Effective Java(中文第二版)》【PDF】下载

    <Effective Java(中文第二版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382186 Java(中文第二版)& ...

  9. Effective Java 第三版——48. 谨慎使用流并行

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

随机推荐

  1. mysql 中语句执行的顺序以及查询处理阶段的分析

    原文链接:http://www.php.cn/mysql-tutorials-408865.html 本篇文章给大家带来的内容是关于mysql中语句执行的顺序以及查询处理阶段的分析,有一定的参考价值, ...

  2. python脚本解析json文件

    python脚本解析json文件 没写完.但是有效果.初次尝试,写的比较不简洁... 比较烦的地方在于: 1,中文编码: pSpecs.decode('raw_unicode_escape') 2,花 ...

  3. topcoder srm 691 div1 -3

    1.给定一个$n$个顶点$n$个边的图,边是$(i,a_{i})$,顶点编号$[0,n-1]$.增加一个顶点$n$,现在选出一个顶点集$M$,对于任意的在$M$中 的顶点$x$,去掉边$(x,a_{x ...

  4. Google Protocol Buffer在vs2010下配置

    1.从这里下载protobuf-2.6.1.tar.gz到桌面,并解压,解压后的文件夹为protobuf-2.6.1.(我的桌面为C:\Users\mcl\Desktop) 2 .进入文件夹proto ...

  5. Mac通过安装Go2Shell实现“在当前目录打开iTerm2”

    先上效果图: 1.从官网下载最新的版本,不要从苹果商店下载,因为苹果商店的版本比较旧,只支持Finders10.6~10.10,不支持最新的版本 http://zipzapmac.com/Go2She ...

  6. bzoj1741 [Usaco2005 nov]Asteroids 穿越小行星群 最小点覆盖

    链接 https://www.lydsy.com/JudgeOnline/problem.php?id=1741 思路 消除所有的小行星 每个点(x,y)只有选择x或者y才能被覆盖 二分图最小点覆盖= ...

  7. sql server查看用户权限

    System.ServiceModel.FaultException: Server error. Detail: The EXECUTE permission was denied on the o ...

  8. LOJ6284 数列分块入门8(分块)

    两个锅 一个是sametag[i]==c 另一个是a[j]不要写成a[i] #include <cstdio> #include <cstring> #include < ...

  9. map数据结构

    学习map的这种ES6新加的数据结构.在一些构建工具中是非常喜欢使用map这种数据结构来进行配置的,因为map是一种灵活,简单的适合一对一查找的数据结构.我们知道的数据结构,已经有了json和set. ...

  10. 微信发送红包示例(php)

    微信红包接口 微信红包是微信支付推出的一款基于微信客户端的免费服务应用,微信红包以微信支付 为核心安全保障,为广大用户提供安全,快捷的移劢支付服务. 请求URL 现金红包 https://api.mc ...