- Thread抛出异常就死亡了。但是线程池却会生成一个新的线程
尽量使用接口引用对象
不用接口引用的情况:
没有合适的接口的情况。例如: 值类型,String和StringBuilder,Random。通常是final类型.
如果程序依赖于实现了某个接口的类的额外方法,例如LinkedHashMap
不要使用字符串连接操作符来合并多个字符串,除非性能无关紧要。相反,应该使用StringBuilder的append方法。另一种方法是,使用字符数组,或者每次只处理一个字符串,而不是将它们组合起来。
以为字符串的不可变,当两个字符串连接在一起时,他们的内容就会被拷贝
1 | StringBuilder b = new StringBuilder(numItems() * LINE_WIDTH); |
本节我们不使用Spring配置方式,使用DUBBO提供的API来做。
本节使用API的方式搭建了一个服务提供(Provider),服务注册中心(Registry),服务消费(Consumer)的分布式系统。在非Spring环境下,可以尝试使用这种方式
foreach可以遍历iterable接口
foreach循环在简洁性与预防bug方面有着传统的for循环无法比拟的优势.
除了一下情况:
过滤- 将删除特定元素remove方法
转换- 使用列表迭代器或者数组索引,以便设定元素的值
平行迭代- 如果并行遍历多个集合,就需要显示的控制迭代器和索引变量
http://blog.csdn.net/zhtzyh2012/article/details/46675065
循环提供特殊机会将变量作用域最小化.(无论传统for,还foreach).for循环,都允许声明循环变量,它们的作用域被限定在正好的作用范围之内.(范围包括循环体,以及循环体之前的初始化,测试,更新).如果循环终止之后不再需要循环变量内容,for循环优于while循环.
几乎每个局部变量的声明都应该包含一个初始化表达式.如果没有足够信息来对一个变量进行有意义的初始化,就应该推迟这个声明,直到可以初始化为止.例外情况是与try..catch有关.
for循环比while循环另外优势:更简短,增加可读性.
1 | public static void main(String[] args) { |
1 | private static final class ProxyClassFactory |
1 | package com.sun.proxy; |
1 | public Object getProxy(){ |
1 | public static Object newProxyInstance(ClassLoader loader, |
1 | private static Class<?> getProxyClass0(ClassLoader loader, |
1 | public V get(K key, P parameter) { |
最好不要用序数来索引数组,而要使用EnumMap
EnumMap源代码学习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 public V put(K key, V value) {
typeCheck(key);
int index = key.ordinal();
Object oldValue = vals[index];
vals[index] = maskNull(value);
if (oldValue == null)
size++;
return unmaskNull(oldValue);
}
public V remove(Object key) {
if (!isValidKey(key))
return null;
int index = ((Enum<?>)key).ordinal();
Object oldValue = vals[index];
vals[index] = null;
if (oldValue != null)
size--;
return unmaskNull(oldValue);
}
public V get(Object key) {
return (isValidKey(key) ?
unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}
public boolean containsKey(Object key) {
return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
}
引用自: https://mp.weixin.qq.com/s/bvqVBnYPdFvpQqdB_4kdUQ
volatile 能使得一个非原子操作变成原子操作吗?
一个典型的例子是在类中有一个long 类型的成员变量。如果你知道该成员变量会被多个线程访问,如计数器、价格等,你最好是将其设置为 volatile。为什么?因为 Java 中读取long 类型变量不是原子的,需要分成两步,如果一个线程正在修改该 long 变量的值,另一个线程可能只能看到该值的一半(前 32 位)。但是对一个 volatile 型的 long 或double 变量的读写是原子。
volatile 类型变量提供什么保证?
volatile 变量提供顺序和可见性保证,例如,JVM或者 JIT为了获得更好的性能会对语句重排序,但是 volatile 类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。某些情况下,volatile 还能提供原子性,如读 64 位数据类型,像 long 和 double 都不是原子的,但 volatile 类型的 double 和 long 就是原子的。
volatile 修饰符的有过什么实践?
一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写。double 和 long 都是64位宽,因此对这两种类型的读是分为两部分的,第一次读取第一个 32 位,然后再读剩下的 32 位,这个过程不是原子的,但Java 中 volatile 型的 long 或 double 变量的读写是原子的。volatile 修复符的另一个作用是提供内存屏障(memory barrier),例如在分布式框架中的应用。简单的说,就是当你写一个 volatile 变量之前,Java 内存模型会插入一个写屏障(writebarrier),读一个volatile 变量之前,会插入一个读屏障(read barrier)。意思就是说,在你写一个volatile 域时,能保证任何线程都能看到你写的值,同时,在写之前,也能保证任何数值的更新对所有线程是可见的,因为内存屏障会将其他所有写的值更新到缓存。
实现函数对象的几种方式:
- C语言的函数指针
- lambda表达式
- 函数式接口
函数对象主要用于策略模式.只用一次的话,使用匿名内部类;多次使用的话,可以导出成一个成员域(static final修饰)
实例:
java.util.Comparator