目录
一、模拟 CAS(Compare And Swap) 自旋锁来实现
四、基于 ReentrantLock 锁使用 CAS 的思想来实现
一、模拟 CAS(Compare And Swap) 自旋锁来实现
//静态的全局变量被创建的所有该类的对象共享,在类的方法中也是共享的
//所以被所有线程访问和修改,使用需要注意线程的安全性
static boolean b = true;
//模拟 CAS(Compare And Swap) 自旋锁来实现
public static void casTest() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i < 7; i++) {
//使用 where 循环,因为当条件不成立,程序就会在此一直等待
while (!b) {}
System.out.print(i);
b = false;
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (char i = 97; i < 103; i++) {
while (b) {}
System.out.print(i);
b = true;
}
}
});
t1.start();
t2.start();
}
问题总结:
匿名内部类访问外部方法的局部变量会自动添加 final 关键字,常量不能被修改。
对于内部类的使用可以参考Java 中的内部类的定义-CSDN博客
二、使用 synchronized 同步锁实现
//使用 synchronized 同步锁实现
public static void synchronizedTest() {
//创建锁的对象,需要该对象是一直保持不变的
Object o = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (o) {
for (int i = 1; i < 7; i++) {
System.out.print(i);
//唤醒一个等待中的线程
o.notify();
/* 线程等待,在类中自定义 wait 方法,
使用 Object 的 wait 方法捕获异常*/
ThreadTest.wait(o);
}
/*一定要在 for 循环跳出之后唤醒另一个等待中的线程,
避免最后一次 for 循环判断条件不成立,不再进入循环体,
无法唤醒另一个线程,导致程序一直无法停止*/
o.notify();
}
}
}, "t1").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (o) {
for (char i = 97; i < 103; i++) {
System.out.print(i);
o.notify();
ThreadTest.wait(o);
}
o.notify();
}
}
}, "t2").start();
}
三、使用 ReentrantLock 锁实现
//使用 ReentrantLock 锁实现
public static void reentrantLockTest() {
/*两个线程都是用同一个 lock 锁
ReentrantLock是一个可重入的互斥锁,它允许线程多次获得同一把锁。
这意味着一个线程可以多次调用lock()方法,而不会导致死锁。*/
Lock lock = new ReentrantLock();
//建立两个 condition 队列来关联两个线程
//Condition是用来实现线程间协调的机制。
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();
new Thread(() -> {
try {
/*lock方法用于获取锁,作用是阻塞当前线程,直到获取到锁为止。
lock方法可以保证在同一时刻只有一个线程能够获得锁,
其他线程会被阻塞,直到锁被释放。*/
lock.lock();
for (int i = 0; i < numArr.length; i++) {
System.out.print(numArr[i]);
//唤醒 c2 队列上等待的线程
c2.signal();
//线程1在 c1 队列上等待
c1.await();
}
c2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t1").start();
new Thread(() -> {
try {
lock.lock();
for (int i = 0; i < letterArr.length; i++) {
System.out.print(letterArr[i]);
//唤醒 c1 队列上等待的一个线程
c1.signal();
//线程2在 c2 队列上等待
c2.await();
}
//避免线程无法跳出for循环的等待
c1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}, "t2").start();
}
四、基于 ReentrantLock 锁使用 CAS 的思想来实现
static boolean flag = true;
//基于 ReentrantLock 锁使用 CAS 的思想来实现
public static void reentrantLockTestPlus() {
Lock lock = new ReentrantLock();
//只用创建一个 condition 队列
Condition condition = lock.newCondition();
//创建一个标志
new Thread(() -> {
try {
lock.lock();
for (int i = 0; i < numArr.length; i++) {
//就相当于上述 CAS 中的 while 循环,一直阻塞方法的进行
if (!flag) {
condition.await();
}
System.out.print(numArr[i]);
flag = false;
condition.signal();
}
/*不用在循环体外再去唤醒等待中的线程,因为 await 的过程在 for 判断之后,
也就是说最后一次 for 判断条件在 await 之前,不会导致程序一直等待结束*/
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t1").start();
new Thread(() -> {
try {
lock.lock();
for (int i = 0; i < letterArr.length; i++) {
if (flag) {
condition.await();
}
System.out.print(letterArr[i]);
flag = true;
condition.signal();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t2").start();
}