多线程的问题
- 正确性
- 安全:竞争条件/死锁
//竞争条件示例:
private static int counter = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}).start();
}
Thread.sleep(100);
System.out.println(counter);
}
控制台结果:
95
- 协同:同时、随机执行的线程,如何协同工作?
- 解决问题的办法:
1. java原生实现
1.1 同步: synchronized
1.2 协同: wait() / notify() / notifyAll()
- 效率与易用性
- 执行地越快越好
- 用起来越不容易出错越好
CAS(compare and swap)
预期值1 -> 新值2 内存中的旧值0
当且仅当更新瞬间, 内存的值 = 预期值 时,才能操作成功;否则,更新失败;
- 乐观锁:
我现在追不到你,过一会再来问; = 自旋锁(spin lock);
private static AtomicInteger counter = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
increment();
}).start();
}
Thread.sleep(100);
System.out.println(counter);
}
private static void increment(){
counter.getAndIncrement();
}
- 悲观锁:
我现在追不到你,就阻塞了;
private static int counter = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
increment();
}).start();
}
Thread.sleep(100);
System.out.println(counter);
}
private synchronized static void increment(){ //synchronized 悲观锁
counter++;
}
潜在问题:
ABA问题;
解决方案:时间戳/版本号;乐观锁 VS 悲观锁实例
ConcurrentHashMap VS Collections.synchronizedMap / HashTable
(Collections.synchronizedMap与hashTable基本上在所有的方法上粗暴的加了synchronized)
附:
mutex = lock
java.util.Collections.SynchronizedMap#mutex
来源于: mutual(共享) + exclusive(排他)