线程的交替打印,实际上涉及的内容是线程间的通信,下面,介绍三种线程间通信实现的交替打印方法和一种非线程间通信的实现方式。
synchronized
是Java中的一个关键字,用于实现对共享资源的互斥访问。wait和notify/notifyAll
是Object类中的两个方法,用于实现线程间的通信。wait
方法会让当前线程释放锁,并进入等待状态,直到被其他线程唤醒。notify/notifyAll
方法会唤醒一个在同一个锁上等待的线程。我们可以使用一个共享变量a来表示当前应该打印哪个字母,初始值为0。当state为0时,表示轮到A线程打印;当a为1时,表示轮到B线程打印;当a为2时,表示轮到C线程打印。每个线程在打印完字母后,需要将a设置为下一个线程的值,以便循环。同时,每个线程还需要唤醒下一个线程,并让自己进入等待状态。
static class m1{
private static int a = 0;
private final static Object lock = new Object();
public void test(){
new Thread(()->{
synchronized(lock){
while(a != 0){
try {
lock.wait();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
System.out.println(Thread.currentThread().getName());
a = 1;
lock.notifyAll();
}
},"AAAAAAAAAAAAAA").start();
new Thread(()->{
synchronized(lock){
while(a != 1){
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(Thread.currentThread().getName());
a = 2;
lock.notifyAll();
}
},"BBBBBBBBBBBBBB").start();
new Thread(()->{
synchronized(lock){
while(a != 2){
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(Thread.currentThread().getName());
a = 0;
lock.notifyAll();
}
},"CCCCCCCCCCCCCC").start();
}
}
ReentrantLock
是Java中的一个类,用于实现可重入的互斥锁,是AQS
的一种实现。Condition
是ReentrantLock
中的一个接口,用于实现线程间的条件等待和唤醒。ReentrantLock
可以创建多个Condition
对象,每个Condition
对象可以绑定一个或多个线程,实现对不同线程的精确控制。我们可以使用一个ReentrantLock
对象作为锁,同时创建三个Condition
对象,分别绑定A、B、C三个线程。每个线程在打印字母之前,需要调用对应的Condition
对象的await方法,等待被唤醒。每个线程在打印字母之后,需要调用下一个Condition
对象的signal
方法,唤醒下一个线程。
static class m2{
private static int state = 0;
private final static ReentrantLock lock = new ReentrantLock();
private final static Condition A = lock.newCondition();
private final static Condition B = lock.newCondition();
private final static Condition C = lock.newCondition();
public void test(){
new Thread(()->{
lock.lock();
try{
while(state != 0){
A.await();
}
System.out.println(Thread.currentThread().getName());
state = 1;
B.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"AAAAAAAAAAAAAA").start();
new Thread(()->{
lock.lock();
try{
while(state != 1){
B.await();
}
System.out.println(Thread.currentThread().getName());
state = 2;
C.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"BBBBBBBBBBBBBB").start();
new Thread(()->{
lock.lock();
try{
while(state != 2){
C.await();
}
System.out.println(Thread.currentThread().getName());
state = 0;
A.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"CCCCCCCCCCCCCC").start();
}
}
Semaphore
是Java中的一个类,用于实现信号量机制。信号量是一种计数器,用于控制对共享资源的访问。Semaphore
可以创建多个信号量对象,每个信号量对象可以绑定一个或多个线程,实现对不同线程的精确控制。我们可以使用三个Semaphore
对象,分别初始化为1、0、0,表示A、B、C三个线程的初始许可数。每个线程在打印字母之前,需要调用对应的Semaphore
对象的acquire
方法,获取许可。每个线程在打印字母之后,需要调用下一个Semaphore
对象的release
方法,释放许可。
static class m3{
private static final Semaphore A = new Semaphore(1);
private static final Semaphore B = new Semaphore(0);
private static final Semaphore C = new Semaphore(0);
public static void test(){
new Thread(()->{
try{
A.acquire();
System.out.println(Thread.currentThread().getName());
B.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"AAAAAAAAAAAAAA").start();
new Thread(()->{
try{
B.acquire();
System.out.println(Thread.currentThread().getName());
C.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"BBBBBBBBBBBBBB").start();
new Thread(()->{
try{
C.acquire();
System.out.println(Thread.currentThread().getName());
A.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"CCCCCCCCCCCCCC").start();
}
}
AtomicInteger是Java中的一个类,用于实现原子性的整数操作。CAS是一种无锁的算法,全称为Compare And Swap,即比较并交换。CAS操作需要三个参数:一个内存地址,一个期望值,一个新值。如果内存地址的值与期望值相等,就将其更新为新值,否则不做任何操作。我们可以使用一个AtomicInteger对象来表示当前应该打印哪个字母,初始值为0。当state为0时,表示轮到A线程打印;当state为1时,表示轮到B线程打印;当state为2时,表示轮到C线程打印。每个线程在打印完字母后,需要使用CAS操作将state设置为下一个线程值,以便循环。
public static class m4{
private static volatile AtomicInteger state = new AtomicInteger(0);
public void test(){
new Thread(()->{
while(state.get() == 0){
System.out.println(Thread.currentThread().getName());
state.compareAndSet(state.get(), 1);
}
},"AAAAAAAAAAAAAA").start();
new Thread(()->{
while(state.get() == 1){
System.out.println(Thread.currentThread().getName());
state.compareAndSet(state.get(), 2);
}
},"BBBBBBBBBBBBBB").start();
new Thread(()->{
while(state.get() == 2){
System.out.println(Thread.currentThread().getName());
state.compareAndSet(state.get(), 0);
}
},"CCCCCCCCCCCCCC").start();
}
}