学习方式:跳出来看全景;钻进去看本质。
并发编程领域的三个核心问题:分工、同步和互斥
并发场景:
微观:缓存带来的可见性问题;线程切换带来的原子性问题;编译优化带来的有序性问题;
宏观:安全性、活跃性、性能问题
原子性问题
一个或多个操作在CPU执行的过程中不被中断,成为原子性。原子性问题的根源是线程切换,现代的解决方案依赖于对临界资源的互斥操作。
示例:
实现两个线程交替输出奇数偶数:
synchronized
public void printNumber() {
int[] count = {1};
String lock = "lock";
Thread oddThread = new Thread(() -> {
synchronized (lock) {
while(count[0] < 100) {
while(count[0] %2 != 1) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + count[0]);
count[0]++;
lock.notifyAll();
}
}
});
Thread evenThread = new Thread(() -> {
synchronized (lock) {
while(count[0] < 100) {
while(count[0] %2 != 0) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + count[0]);
count[0]++;
lock.notifyAll();
}
}
});
oddThread.start();
evenThread.start();
}
ReentrantLock
public void printNumber() {
ReentrantLock reentrantLock = new ReentrantLock();
Condition condition = reentrantLock.newCondition();
int[] count = {1};
Thread oddThread = new Thread(() -> {
reentrantLock.lock();
try {
while (count[0] < 100) {
while (count[0] % 2 != 1) {
condition.await();
}
System.out.println(Thread.currentThread().getName() + ":" + count[0]);
count[0] ++;
condition.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
});
Thread evenThread = new Thread(() -> {
reentrantLock.lock();
try {
while (count[0] < 100) {
while (count[0] % 2 != 0) {
condition.await();
}
System.out.println(Thread.currentThread().getName() + ":" + count[0]);
count[0] ++;
condition.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
});
oddThread.start();
evenThread.start();
}