第一种:使用wait()、notify()
/**
* @author huangke
* @date 2021/7/14 11:33
*
* wait()/notify() 的方法
*/
public class JiaoTiShuziZimu1 {
// 要严格保证先打数字再打字母的顺序,就必须加这个volatile变量
static volatile Boolean flag = true;
public static void main(String[] args) {
Object obj = new Object();
// 如何保证t1一定在t2前运行,加一个flag标识
Thread t1 = new Thread(() -> {
synchronized (obj){
try {
for (int i = 1; i <= 26;) {
if (flag){
System.out.println(i);
i++;
flag = false;
obj.notify();
}else {
obj.wait();
}
}
obj.wait();
System.out.println("线程1结束了");
// 最后一定要再全部唤醒一次,否则B可能死循环
obj.notify();
}catch (Exception e){
}
}
});
Thread t2 = new Thread(() -> {
synchronized (obj){
try {
for (int i = 1; i <= 26;) {
if (!flag){
System.out.println((char)('a' + i - 1));
i++;
flag = true;
obj.notify();
}else {
obj.wait();
}
}
obj.wait();
System.out.println("线程2结束了");
// 这里不需要再唤醒了,因为已经用flag严格设定顺序了,t2线程一定是最后执行的
// obj.notifyAll();
}catch (Exception e){
}
}
});
t2.start();
t1.start();
}
}
对第一种的优化:
/**
* @author huangke
* @date 2021/7/14 11:33
*
* wait()/notify() 的方法
*/
public class JiaoTiShuziZimu1 {
// 要严格保证先打数字再打字母的顺序,就必须加这个volatile变量
static volatile Boolean flag = true;
public static void main(String[] args) {
Object obj = new Object();
// 如何保证t1一定在t2前运行,加一个flag标识
Thread t1 = new Thread(() -> {
synchronized (obj){
try {
// 这个线程一致行就修改flag的值。以确保线程2可以执行
flag = false;
for (int i = 1; i <= 26;) {
System.out.println(i);
i++;
obj.notify();
obj.wait();
}
System.out.println("线程1结束了");
// 最后一定要再全部唤醒一次,否则B可能死循环
obj.notify();
}catch (Exception e){
}
}
});
Thread t2 = new Thread(() -> {
synchronized (obj){
try {
// 如果先进了这里,就先等待、唤醒t1
if (flag){
obj.wait();
obj.notify();
}
for (int i = 1; i <= 26; i++) {
System.out.println((char)('a' + i - 1));
obj.notify();
obj.wait();
}
System.out.println("线程2结束了");
// 这里不需要再唤醒了,因为已经用flag严格设定顺序了,t2线程一定是最后执行的
// obj.notifyAll();
}catch (Exception e){
}
}
});
t1.start();
t2.start();
}
}
第二种:使用LockSupport
/**
* @author huangke
* @date 2021/7/14 11:33
*
* LockSupport的方法
*/
public class JiaoTiShuziZimu2 {
public static void main(String[] args) {
Print print1 = new Print();
Print print2 = new Print();
Thread t1 = new Thread(print1);
Thread t2 = new Thread(print2);
t1.setName("t1");
t2.setName("t2");
print1.setFlag(true);
print1.setT(t2);
print2.setFlag(false);
print2.setT(t1);
t2.start();
t1.start();
}
static class Print implements Runnable {
private volatile Thread t;
private boolean flag;
@Override
public void run() {
if (!flag){
// flag为false的先阻塞
LockSupport.park();
}
for (int i = 1; i <= 26; i++) {
if (flag){
System.out.println(i);
}else {
System.out.println((char)(i + 'a' - 1));
}
// 唤醒另一个线程
LockSupport.unpark(t);
// 堵塞自己
LockSupport.park();
}
System.out.println(Thread.currentThread().getName() + "执行完了");
if (flag){
// flag为true的是先执行了,执行完了还要再唤醒另一个
LockSupport.unpark(t);
}
}
public void setT(Thread t) {
this.t = t;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
}
第三种:使用Conditon队列
/**
* @author huangke
* @date 2021/7/14 11:33
*
* Condition队列的方法
*/
public class JiaoTiShuziZimu3 {
static volatile boolean flag = true;
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition conditionT1 = lock.newCondition();
Condition conditionT2 = lock.newCondition();
Thread t1 = new Thread(() -> {
try {
lock.lock();
flag = false;
for (int i = 1; i <= 26; i++) {
System.out.println(i);
// 叫醒t2
conditionT2.signal();
// 加入t1并wait()
conditionT1.await();
}
conditionT2.signal();
System.out.println("队列1结束运行");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
});
Thread t2 = new Thread(() -> {
try {
lock.lock();
if (flag){
// 加入t2并wait()
conditionT2.await();
}
for (int i = 1; i <= 26; i++) {
System.out.println((char)(i + 'a' - 1));
// 叫醒t1
conditionT1.signal();
// 加入t2并wait()
conditionT2.await();
}
conditionT1.signal();
System.out.println("队列2结束运行");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
});
t2.start();
t1.start();
}
}