Java Serial
1. Java基础问答
2. Java Generic
3. Latch VS Barrier
4. AtomicInteger, BlockingQueue and Fork/Join
5. ConcurrentHashMap, Executor, ThreadPool
Java基础问答
1. 进程vs线程
2. JVM同步交互机制介绍
3. Synchornized死锁示例
4. 线程状态转换图
5. static
a. 为什么要有静态变量?为什么要有静态方法?普通的成员变量/方法和静态的成员变量/方法含义上有什么区别?
b. 静态变量存在在什么区域?静态方法存放于什么区域?
c. 私有静态方法有什么用?多线程对静态变量有什么影响?
d. 为什么不推荐把对静态变量的访问放于synchronized 块内?
e. 为什么thread的sleep方法是static的
6. final
a. final关键字的作用是什么?final关键字对于多线程有什么帮助,会造成什么不良的后果?
b. 为什么在多线程中,对final变量的取值要取两次
c. 利用final static组合关键字来代替一些枚举类型有什么好处?为什么在很多项目里面,String类型的常量或者模板被统一声明为final static?
7. volatile
a. 为什么 private volatile Integer i = new Integer(2); public int fun() {return i * i;} 是错的?
b. final, volatile一起使用可以吗?
c. happens-before法则是什么?它跟volatile有什么关系
d. volatile是用来修饰变量,而不是方法, 为什么
e. 为什么volatile无法代替锁?
f. synchronized和volatile的区别是什么?在什么时候可以使用volatile变量?
g. 应用volatile的一般场景可以有哪些?
8. Threadsafe
a. 一句话概括出线程安全的含义
b. 为了保证线程安全,我们需要注意什么事情?
c. 我们可以利用哪些手段来保证线程安全?
d. 利用synchronized直接锁住所有访问,有些时候太重了,有什么简单的办法可以即使用synchronized(因为它简单),有可以大幅提高读写性能?
9. synchronized
a. synchronized锁加在什么地方?对哪些部分的访问会被锁住?JVM如何保证只有一个线程在访问?锁的信息存放在哪里
b. synchronized是否可以用到变量上
c. synchronized太重了,有什么其他的锁来替换?偏向锁
d. 什么是死锁, 什么是活锁,如何避免死锁?出现线程死锁如何补救?
e. 为什么构造函数上不能用synchronized
10. Threadlocal
a. 为什么多线程中使用Threadlocal生命对象可以保证线程安全?
b. Threadlocal如何保证key是唯一的?
c. 线程run方法里面声明的变量为什么不需要使用Threadlocal来保证线程安全?
d. 什么时候需要使用Threadlocal以保证线程安全?
11. fail-fast和fail-safe
a. 为什么不能对java collection一边遍历一边删除?
b. 为什么能对juc可以一边遍历一边删除?
Java generic
1. 泛型是什么
2. 泛型的作用
3. 泛型实现原理:编译器擦除
a. 泛型是编译器中的概念,JVM没有泛型这样的概念,编译器用擦除法实现泛型。
b. 擦除演示
c. 擦除引起的问题及解决方法(参考http://blog.csdn.net/lonelyroamer/article/details/7868820)
i. 类型擦除所带来的多态麻烦
ii. 泛型类型变量不能是基本数据类型
iii. 异常中使用泛型的问题
iv. 不能声明参数化类型的数组
v. 泛型类型的实例化
vi. 类型擦除后的冲突(比如equals方法)
d. 其它常见问题
i. 泛型中 参数化类型不考虑继承关系
ii. 参数化类型与原始类型的兼容
4. 存取原则和PECS(Producer Extends, Consumer Super)法则
a. 泛型中的” ”通配符
b. 泛型中的” ”通配符的扩展
c. PECS法则
i. 如果你想从一个数据类型里获取数据,使用 extends 通配符
ii. 如果你想把对象写入一个数据结构里,使用 super 通配符
iii. 如果你既想存,又想取,那就别用通配符。
5. 为什么Java的泛型伪泛型
Latch and Barrier
1. Latch
a. latch就像一把大锁,所有调用它的await方法的线程都会被阻塞在那里,直到有足够的线程调用它的countDown方法,那些被阻塞的线程才会继续运行。
b. latch最主要的方法有两个,一个是await,另一个是countDown。
i. 当一个线程调用await方法时,该线程会被阻塞起来。
ii. 当一个线程调用countDown方法时,该线程不会被阻塞,会继续运行下去。
iii. latch在实例化的时候,需要属于一个参数用于指明在阻塞线程被唤起之前,需要调用countDown方法的次数。
iv. latch的await还提供了一种方法await(long timeout, TimeUnit unit)用来设定线程的最大阻塞时间。如果线程阻塞时间超过这个时间设置,但countDown方法的调用次数依然没有达到被唤醒的条件,该线程会放弃阻塞,被唤醒。
c. LatchSample.java是一个简单的使用CountDownLatch的例子。
d. latch的实例化对象不可以被反复使用,去掉上面例子中main方法中的倒数第二第三行的注销,执行代码,可以看到当第二次使用时,打印"All end."这一句的方法并没有在其它线程执行完了以后才被执行。
2. barrier
a. barrier类似一个同步所有线程的栅栏,它让所有执行到特定行的线程同时等待,直到等待的线程数目达到一定的数目,所有线程再又同时开始执行。
b. 和latch不同的是,barrier是可以被反复使用的。
c. barrier最主要的就是一个方法await。
i. 当一个线程调用await方法时,该线程会被阻塞起来。
ii. barrier实例化的时候,需要属于一个参数用于指明在阻塞线程被唤起之前,需要调用await方法的次数。当await方法被调用次数达到该次数时,所有被阻塞的线程被唤醒开始运行,此时barrier对await方法调用次数的计数将重新开始。
iii. barrier在实例化的时候,传入一个实现Runnable接口的对象作为唤醒所有线程前被执行的回调函数。这个回调函数是通过run()方法执行的,而不是start()方法,所以它不是一个和其他线程并行执行的线程,这个回调函数的执行会阻塞其他所有被await阻塞的线程,直到这个回调函数被执行完了之后,其他被阻塞线程才能开始执行。所以尽量不要在这个回调函数中去执行计算时间比较长的方法。
d. BarrierSample.java是一个简单的使用CyclicBarrier的例子。在这个例子中,CyclicBarrier的一个实例化对象被连续使用