Java实现新建三个线程,每个线程顺序打印5个数字,打印到100

发布时间 2023-04-02 16:21:40作者: iscanghai
  • 方法一:synchronized + wait + notify
//三个线程循环打印数字,每个打印5个,打印数字到num
class WaitNotifyABC{
    private volatile int num = 0;//线程共享变量

    /**Object 和 this都可以对同步代码块加锁,但是this锁的是类的实例,如果该实例被他人拿走,
    则本线程永远拿不到锁。Object也可以通过反射获取,但相比于this多一层保护。
    为什么final?因为防止LOCK被重新赋值,相当于被其他线程抢走锁。*/
    private static final Object LOCK = new Object();
   
    private void printABC(int targetNum){
        while(num <= 100){
            synchronized(LOCK){
                /*用if会造成假唤醒的问题,如果if,执行了wait之后,被唤醒了就不会再判断if条件。
                 while被唤醒之后会先执行while内的判断条件,避免在wait期间判断条件发生变化。*/
                while(num % 3 != targetNum){
                    try {
                        LOCK.wait();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                for (int i = 0; i < 5; i++) {
                    num++;
                    if(num > 100){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "-->" + String.valueOf(num));
                }
                LOCK.notifyAll();
            }
        }
    }

    public static void main(String[] args) {
        WaitNotifyABC waitNotifyABC = new WaitNotifyABC();
        new Thread(() -> {
            waitNotifyABC.printABC(0);
        },"线程A").start();
        new Thread(() ->{
            waitNotifyABC.printABC(2);
        },"线程B").start();
        new Thread(() -> {
            waitNotifyABC.printABC(1);
        },"线程C").start();
    }
}
  •  方法二:Lock

Lock方法和synchronized方法相似,对同步代码块加锁,无论哪个线程拿到锁之后都需要满足num%3 == targetNum才能执行。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockABC {
    private volatile int num = 0;
    private Lock lock = new ReentrantLock();

    private void printABC(int targetNum){
        while(num <= 100){
            lock.lock();
            if(num % 3 == targetNum){
                for (int i = 0; i < 5; i++) {
                    num++;
                    if(num > 100){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "-->" + String.valueOf(num));
                }
            }
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        LockABC lockABC = new LockABC();
        new Thread(() -> {
            lockABC.printABC(0);
        },"线程A").start();
        new Thread(() -> {
            lockABC.printABC(2);
        },"线程B").start();
        new Thread(() -> {
            lockABC.printABC(1);
        },"线程C").start();
    }
    
}
  • 方法三:Lock+Condition
import java.net.CacheRequest;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockCondition {
    private volatile int num = 0;
    private Lock lock = new ReentrantLock();
    private Condition ca = lock.newCondition();
    private Condition cb = lock.newCondition();
    private Condition cc = lock.newCondition();

    private void printABC(int targetNum, Condition currentThread, Condition nextThread){
        while(num <= 100){
            lock.lock();
            try {
                while(num % 3 != targetNum){
                    if(num > 100){
                        break;
                    }
                    currentThread.await();
                }
                for (int i = 0; i < 5; i++) {
                    num++;
                    if(num > 100){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "-->" + String.valueOf(num));
                }
                nextThread.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally{
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        LockCondition lockCondition = new LockCondition();
        new Thread(() -> {
            lockCondition.printABC(0, lockCondition.ca, lockCondition.cb);
        },"线程A").start();
        new Thread(() -> {
            lockCondition.printABC(2, lockCondition.cb, lockCondition.cc);
        },"线程B").start();
        new Thread(() -> {
            lockCondition.printABC(1, lockCondition.cc, lockCondition.ca);
        },"线程C").start();
    }
}
  • 方法四:Semophore
import java.util.concurrent.Semaphore;
public class SemaphoreABC {
    private volatile int num = 0;
    private Semaphore sa = new Semaphore(1);
    private Semaphore sb = new Semaphore(0);
    private Semaphore sc = new Semaphore(0);
    private void printABC(Semaphore currentThread, Semaphore nextThread){
        while(num <= 100){
            try {
                currentThread.acquire();
                for (int i = 0; i < 5; i++) {
                    num++;
                    if(num > 100){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "-->" + String.valueOf(num));
                }
                nextThread.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        SemaphoreABC semaphoreABC = new SemaphoreABC();
        new Thread(() -> {
            semaphoreABC.printABC(semaphoreABC.sa, semaphoreABC.sb);
        },"线程A").start();;
        new Thread(() -> {
            semaphoreABC.printABC(semaphoreABC.sb, semaphoreABC.sc);
        },"线程B").start();;
        new Thread(() -> {
            semaphoreABC.printABC(semaphoreABC.sc, semaphoreABC.sa);
        },"线程C").start();;
    }
}