我们天天说锁,锁到底是什么?参考
涉及到知识点:
- volatile 可见性
- CAS 机制保证原子性操作
- 线程通信
锁保证竞争条件下,只能有一个线程去处理业务逻辑。
1、怎么表示锁被占用?被谁占用?
volatile修饰变量Thread owner,变量不为null,表示占用
2、如何保证锁的争夺是原子性的?
CAS机制 — 用一个预期的值和内存值进行比较,如果两个值相等,就用预期的值替换内存值,并返回 true。否则,返回 false。
private volatile AtomicReference<Thread> owner = new AtomicReference<Thread>();
// CAS机制拿当前线程跟主内存中的值对比,owner是否为null,如果是就将其值设置为当前线程
owner.compareAndSet(null, Thread.currentThread());
3、抢不到锁的线程如何阻塞?阻塞后改如何唤醒呢?
线程通信,park/unpark
4、抢不到锁的线程该怎么保存?private volatile LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();
释放锁:
public void unlock() {
// CAS机制拿当前线程跟主内存中的值对比,是否是同一个线程,如果是就将其值设置为null
if (owner.compareAndSet(Thread.currentThread(), null)) {
// 将所有阻塞等待队列的线程都唤醒,让他们去抢锁。(非公平)
if (CollectionUtils.isNotEmpty(waiters)) {
waiters.stream().forEach(waiter -> {
LockSupport.unpark(waiter);
});
}
}
}
【线程AB交替打印AB】
参考
通过synchronized上锁,配合boolean变量完成交替打印
public class ThreadWhileDemo {
private static boolean startA = true;
private static boolean startB = false;
public static void main(String[] args) {
final Object singal = new Object();
new Thread(() -> {
// 上锁
synchronized(singal){
while (true) {
if (startA) {
System.out.print("A");
startA = false;
startB = true;
singal.notify();
}else{
try {
singal.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
new Thread(() -> {
synchronized(singal){
while (true) {
if (startB) {
System.out.print("B");
startA = true;
startB = false;
singal.notify();
}else{
try {
singal.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
}
ReentrantLock 可以实现手动加锁,同时配合Condition可以随心所欲地控制多个线程的执行顺序。
public class ReenterLockDemo {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
new Thread(() -> {
lock.lock();
for (int i = 0; i < 10; i++) {
System.out.print("A");
conditionB.signal();
try {
conditionA.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 这里有个坑,要记得在循环之后调用signal(),否则线程可能会一直处于await状态
conditionB.signal();
lock.unlock();
}).start();
new Thread(() -> {
lock.lock();
for (int i = 0; i < 10; i++) {
System.out.print("B");
conditionA.signal();
try {
conditionB.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
conditionA.signal();
lock.unlock();
}).start();
}
}
【实现一个死锁】
主要思路:有两个锁,线程AB各把持一个
public class DeadLockDemo {
public static void main(String[] args) {
// 上两把锁
final Object o1 = new Object();
final Object o2 = new Object();
// 通过lambda表达式,完成Runable implement
new Thread(() -> {
synchronized(o1){
System.out.println("我上锁o1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(o2){
System.out.println("我应该到不了这,谁知道呢");
}
}
}).start();
// 继承方式
new Thread(){
public void run() {
synchronized(o2){
System.out.println("I lock o2");
synchronized(o1){
System.out.println("Unreachable site...");
}
}
};
}.start();
}
}
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/274098.html