交替打印数字
利用volatile同步
public class VolatilePrint {
// 全局变量i,用于计数
private static int i = 1;
// 是否是奇数的标志,用volatile保证可见性
private static volatile boolean isOdd = true;
public static void main(String[] args) {
// 线程A,负责打印奇数
new Thread(() -> {
while (i <= 100) {
if (isOdd) {
// 打印奇数
System.out.println(Thread.currentThread().getName() + ":" + i++);
// 打印完奇数后,将标志设为false
isOdd = false;
}
}
}, "Thread-A").start();
// 线程B,负责打印偶数
new Thread(() -> {
while (i <= 100) {
if (!isOdd) {
// 打印偶数
System.out.println(Thread.currentThread().getName() + ":" + i++);
// 打印完偶数后,将标志设为true
isOdd = true;
}
}
}, "Thread-B").start();
}
}
利用wait()/notify()同步
public class WaitNotify {
// 全局变量i,用于计数
public static int i = 1;
// 锁对象,用于线程同步
public static final Object lock = new Object();
public static void main(String[] args) {
// 线程A,负责打印奇数
new Thread(() -> {
synchronized (lock) {
while (i <= 100) {
if (i % 2 == 1) {
// 打印奇数
System.out.println(Thread.currentThread().getName() + ":" + i++);
// 唤醒其他线程
lock.notify();
} else {
try {
// 当前线程等待,释放锁
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}, "Thread-A").start();
// 线程B,负责打印偶数
new Thread(() -> {
synchronized (lock) {
while (i <= 100) {
if (i % 2 == 0) {
// 打印偶数
System.out.println(Thread.currentThread().getName() + ":" + i++);
// 唤醒其他线程
lock.notify();
} else {
try {
// 当前线程等待,释放锁
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}, "Thread-B").start();
}
}
使用Semaphore信号量
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
// 全局变量i,用于计数
private static int i = 1;
// 奇数信号量,初始许可数为1
private static Semaphore semaphoreOdd = new Semaphore(1);
// 偶数信号量,初始许可数为0
private static Semaphore semaphoreEven = new Semaphore(0);
public static void main(String[] args) {
// 线程A,负责打印奇数
new Thread(() -> {
while (i <= 100) {
try {
// 获取奇数信号量,获取后许可数变为0
semaphoreOdd.acquire();
// 打印奇数
System.out.println(Thread.currentThread().getName() + ":" + i++);
// 释放偶数信号量,许可数加1
semaphoreEven.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Thread-A").start();
// 线程B,负责打印偶数
new Thread(() -> {
while (i <= 100) {
try {
// 获取偶数信号量,获取后许可数变为0
semaphoreEven.acquire();
// 打印偶数
System.out.println(Thread.currentThread().getName() + ":" + i++);
// 释放奇数信号量,许可数加1
semaphoreOdd.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Thread-B").start();
}
}
使用Condition和Lock
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionExample {
// 全局变量i,用于计数
private static int i = 1;
// 可重入锁
private static final Lock lock = new ReentrantLock();
// 奇数条件变量
private static final Condition conditionOdd = lock.newCondition();
// 偶数条件变量
private static final Condition conditionEven = lock.newCondition();
public static void main(String[] args) {
// 线程A,负责打印奇数
new Thread(() -> {
lock.lock(); // 加锁
try {
while (i <= 100) {
if (i % 2 == 1) {
// 打印奇数
System.out.println(Thread.currentThread().getName() + ": " + i++);
// 唤醒偶数条件变量等待的线程
conditionEven.signal();
} else {
// 当前线程等待在奇数条件变量上,释放锁
conditionOdd.await();
}
}
// 结束时,唤醒对方线程,防止阻塞
conditionEven.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
}, "Thread-A").start();
// 线程B,负责打印偶数
new Thread(() -> {
lock.lock(); // 加锁
try {
while (i <= 100) {
if (i % 2 == 0) {
// 打印偶数
System.out.println(Thread.currentThread().getName() + ": " + i++);
// 唤醒奇数条件变量等待的线程
conditionOdd.signal();
} else {
// 当前线程等待在偶数条件变量上,释放锁
conditionEven.await();
}
}
// 结束时,唤醒对方线程,防止阻塞
conditionOdd.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
}, "Thread-B").start();
}
}
使用AQS
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class AQSSyncExample {
// 全局变量i,用于计数
private static int i = 1;
// 自定义AQS类,负责奇偶数线程的同步
private static class MyAQS extends AbstractQueuedSynchronizer {
public MyAQS() {
// 初始状态为1,表示奇数线程先执行
setState(1);
}
// 打印奇数
public void printOdd(Runnable printOdd) {
acquire(1); // 获取状态为1的许可
printOdd.run(); // 执行打印操作
release(0); // 释放状态为0的许可
}
// 打印偶数
public void printEven(Runnable printEven) {
acquire(0); // 获取状态为0的许可
printEven.run(); // 执行打印操作
release(1); // 释放状态为1的许可
}
@Override
protected boolean tryAcquire(int arg) {
return getState() == arg; // 获取许可时,判断当前状态是否匹配
}
@Override
protected boolean tryRelease(int arg) {
setState(arg); // 释放许可时,设置新的状态
return true;
}
}
public static void main(String[] args) {
MyAQS aqs = new MyAQS();
// 线程A,负责打印奇数
new Thread(() -> {
while (i <= 100) {
aqs.printOdd(() -> {
// 打印奇数
System.out.println(Thread.currentThread().getName() + ": " + i++);
});
}
}, "Thread-A").start();
// 线程B,负责打印偶数
new Thread(() -> {
while (i <= 100) {
aqs.printEven(() -> {
// 打印偶数
System.out.println(Thread.currentThread().getName() + ": " + i++);
});
}
}, "Thread-B").start();
}
}
使用LockSupport
import java.util.concurrent.locks.LockSupport;
public class LockSupportExample {
// 全局变量i,用于计数
private static int i = 1;
// 线程引用,用于唤醒对方线程
private static Thread threadA, threadB;
public static void main(String[] args) {
// 线程A,负责打印奇数
threadA = new Thread(() -> {
while (i <= 100) {
if (i % 2 == 1) {
// 打印奇数
System.out.println(Thread.currentThread().getName() + ": " + i++);
// 唤醒线程B
LockSupport.unpark(threadB);
// 当前线程等待
LockSupport.park();
}
}
// 结束时,防止对方线程被永远阻塞
LockSupport.unpark(threadB);
}, "Thread-A");
// 线程B,负责打印偶数
threadB = new Thread(() -> {
while (i <= 100) {
// 当前线程等待
LockSupport.park();
if (i % 2 == 0) {
// 打印偶数
System.out.println(Thread.currentThread().getName() + ": " + i++);
// 唤醒线程A
LockSupport.unpark(threadA);
}
}
}, "Thread-B");
// 启动线程
threadA.start();
threadB.start();
}
}