Effective Java学习概括

并发编程

  1. Executors.newSingleThreadExecutor()
  2. Executors.newFixedThreadPool(int)
  3. Executors.newCachedThreadPool()

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式

  1. ForkJoinPool

ForkJoinPool是自java7引入的线程池,jvm提供的一个用于并行执行的任务框架。其主旨是将大任务分成若干小任务,之后再并行对这些小任务进行计算,最终汇总这些任务的结果。得到最终的结果。其广泛用在java8的stream中。
work-stealing(工作窃取),ForkJoinPool提供了一个更有效的利用线程的机制,当ThreadPoolExecutor还在用单个队列存放任务时,ForkJoinPool已经分配了与线程数相等的队列,当有任务加入线程池时,会被平均分配到对应的队列上,各线程进行正常工作,当有线程提前完成时,会从队列的末端“窃取”其他线程未执行完的任务,当任务量特别大时,CPU多的计算机会表现出更好的性能

  1. 类锁和对象锁
  2. synchronized 修饰方法、代码块,修饰不同地方分别对应类锁或对象锁
  3. notify(), notifyAll()

没有理由在新代码中使用wait 和 notify,即使有,也是极少

  1. 出现 synchronized 修饰符不代表该方法是线程安全的

这句话其实是表明要正确使用synchronized。

  1. 公平锁和非公平锁。自旋锁
  2. 原子性(atomicity),可视性(volatility)
  3. wait()和sleep()
  4. Condition:await(),signal(),signalAll()
  5. CountDownLatch,CyclicBarrier:用来同步一个或多个任务,强制它们等待由其他任务执行的一组操作完成
  6. Timer定时任务原理基本理解,单线程 + 最小堆 + 不断轮询
  7. Timer、ScheduledThreadPool、DelayQueue,Quartz
  8. 由于ScheduledThreadPool的实现是从queue里拿到第一个任务后时间未到则sleep到该任务的时间,假如sleep 10s,这个时候进来一个任务是5s后执行,那是不是非要等sleep 10s后执行了前一个任务再执行新任务呢,很显然不能这么设计。所以在加入queue时会判断:如果queue为空,则唤醒线程,如果加入的任务排第一,则也会唤醒线程。
  9. 时间轮算法Netty实现:转数。kafka实现:多层时间轮。
  10. Greenplum数据库、ServiceMesh、Datahub、非侵入打点技术
  11. 编程范式:
  1. 面向对象:封装、继承、多态
  2. 面向过程:只关心解决问题的步骤与过程
  3. 函数式编程:程序看作函数,输入自变量,输出因变量,函数像变量一样作为参数传递。
  4. 面向接口编程:属于面向对象体系的一部分,多态与抽象
  1. JVisualVM ,JDK提供的一个JVM运行监控可视化工具
  2. lock 域应该始终声明为final
  3. 双重检查:在上锁前判断一下,上锁之后再判断一次,若还是失败再执行相应逻辑。
private volatile FieldType field;
private FieldType getField() {
	FieldType result = field;
	if (result == null) {
		synchronized(this) {
			if (field == null)
				field = result = computeFieldValue();
		}
	}
	return result;
}

对于需要用到局部变量result可能有点不理解。这个变量的作用是确保field只在已经被初始化的情况下读取一次。虽然这不是严格需要,但是可以提升性能。

Effective Java

  1. 静态工厂方法
  2. 建造者模式(Builder)
  3. 私有化构造方法实现单例模式
  4. 抽象类是可以被实例化的,只不过是间接:子类实例化时会调用父类构造方法。Calendar是抽象类,从Calendar.getInstance() 中所获得的实例其实就是它的子类 “GreogrianCalendar” 对象。父类引用指向子类对象。
  5. 枚举类被设计为单例模式,构造方法必须私有。jvm会自动实例化枚举对象(使用到时)
  6. 避免创建不必要的对象:比如创建正则表达式的Pattern一次可以用于多次匹配。
private static final Pattern PHONE = Pattern.compile("");
static boolean isPhone(String s){
	return PHONE.matcher(s).matches();
}
  1. 优先使用基本类型而不是装箱类型
  2. 让程序中的错误尽可能提前暴露
  3. try-with-resources语句代替try-finally:声明了一种或多种资源的try语句(实现了java.lang.AutoCloseable接口的对象,和实现了java.io.Closeable接口的对象,都可以当做资源使用。)
static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                  new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}
  1. native关键字:说明这个方法是本地方法,是指本地编程语言(如C/C++)实现的,并且被编译成了DLL,由java去调用

  2. 覆盖方法的返回类型可以是被覆盖方法返回类型的子类,其他不行

  3. public static int compareUnsigned(int x, int y) {
    return compare(x + MIN_VALUE, y + MIN_VALUE);
    }

  4. 当用final作用于类的成员变量时,成员变量必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。被final修饰的引用变量一旦初始化赋值之后就不能再指向其他的对象

  5. 嵌套类有4种:1.静态成员类,2.非静态成员类,3.匿名类,4.局部类。除了第一种外,其他三种都称为内部类。静态成员类是最简单的一种嵌套类,最好把它看作是普通的类,只是碰巧被声明在另一个类的内部而已。

  6. 当非静态成员类被创建的时候,与外围类的一个实例相关联,这种关联无法被修改

  7. transient关键字:不需要序列化的属性前添加。

  8. 总之,使用原生态类型会在运行时导致异常,因此不要在新代码中使用。原生态类型只是为了与引入泛型之前的遗留代码进行兼容和互用而提供的。让我们做个快速的回顾:Set< Object >是个参数化类型,表示可以包含任何对象类型的一个集合;Set<?>则是一个通配符类型,表示只能包含某种未知对象类型的一个集合;Set则是个原生态类型,她脱离了泛型系统。前两种是安全的,最后一种不安全。

  9. List< E > 和 List<?> 的区别,类型参数和通配符

  10. 可变参数和泛型不能良好地合作,因为可变参数设施是构建在顶级数组之上的一个技术露底,泛型数组有不同的类型规则。

  11. stream的groupingBy(p->p.lifeCycle,()->new EnumMap<>(LifeCycle.class), toSet() ),可以指定映射实现

  12. 枚举的本质是Enum的子类

  13. Enum<E extends Enum> 表示泛型参数就是自己,变成代码就是类似于这样的 public class Test extends Enum

  14. <T extends Enum < T > >这泛型就表示T是个枚举

  15. @Repeatable 可重复的注解

  16. stream流中map和flatmap的用法区别。

  17. 方法引用与lambda表达式

方法引用类型范例Lambda等式
静态Integer::parseIntstr -> Integer.parseInt(str)
有限制Instant.now()::isAfterInstant then = Instant.now() ;t -> then.isAfter(t)
无限制String::toLowerCasestr -> str.toLowerCase()
类构造器TreeMap<K,V>::new() -> new TreeMap<K,V>
数组构造器int[]::newlen -> new int[len]
// 无限流
Stream.iterate(BigInteger.valueOf(2), BigInteger::nextProbablePrime).limit(20).forEach(System.out::print);
Stream.iterate(BigInteger.valueOf(2), t->t.nextProbablePrime()).limit(20).forEach(System.out::print);
  1. 将stream流转为Iterable的适配器方法
public static <E> Iterable<E> iterableOf(Stream<E> stream) {
	return stream::iterator;
	}

有了此方法就可以用for-each语句遍历任何Stream:

for(ProcessHandle p:iterableOf(ProcessHandle.allProcesses())){
}
  1. 重载方法的选择是静态的(编译时确定),而覆盖方法的选择是动态的(选择的依据是被调用方法所在对象的运行时类型)
  2. 正确使用optional才能减少判空代码,不然只是换了判空方式而且还造成额外性能开销。(另外,使用它是显示告诉调用者结果可能为空,因为确保不为空就没必要用它包装)

Optional增添了完全不同于空判断的编程体验,即链式管道流的函数式的编程体验。它的引入是为了在链式管道流(Pipeline)的处理中给延后(Laziness)赋值的情形提供一种统一的处理方式。

  1. 死循环的写法,源码中几乎是for(; ; )

编译器没做优化的前提下:for (;;)相比 while(1) 指令少,不占用寄存器

  1. for-each 循环不仅能遍历集合和数组,还能遍历实现Iterable 接口的任何对象。
public interface Iterable<E>{
	Iterator<E> iterator();
}
  1. 方法抛出受检异常,调用者必须继续传播或者catch。方法抛出运行时异常则可根据业务自行决定处理与否。

抛出运行时异常还是受检异常的主要原则:期望调用者能适当恢复则抛出受检异常。

  1. 失败原子性:失败的方法调用应该使对象保持在被调用之前的状态。
  2. 永远不要反序列化不被信任的数据。

DDD领域驱动

  1. 贫血对象充血对象,领域服务

其他

  1. 与 2 有关的用位运算优化:快速幂算法、取余、判断奇偶数 、乘以2的m次方或除以2的m次方
  2. Sa-Token权限认证框架
  3. TLog是一个轻量级的分布式日志标记追踪框架
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值