并发学习记录08:控制线程运行次序

假如有一个需求,要多线程输出2,然后再输出1,就是要控制多线程输出的顺序,试着去实现

方法1:wait,notify

@Slf4j(topic = "ch.XianChengTongBuTest01")
public class XianChengTongBuTest01 {
    static final Object lock = new Object();
    static boolean t2Run = false;
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (lock) {
                while (!t2Run) {
                    log.debug("t2没运行完,再等等");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("2");
            }
        }, "t1");
        Thread t2 = new Thread(() -> {
            synchronized (lock) {
                log.debug("1");
                lock.notify();
                t2Run = true;
            }
        }, "t2");
        t1.start();
        t2.start();
    }
}

方法2:用park和unpark

@Slf4j(topic = "ch.XianChengTongBuTest02")
public class XianChengTongBuTest02 {
    static boolean t2Run = false;

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            log.debug("t2没运行,t1等着");
            LockSupport.park();
            log.debug("1");
        }, "t1");
        Thread t2 = new Thread(() -> {
            log.debug("2");
            LockSupport.unpark(t1);
        }, "t2");
        t1.start();
        t2.start();
    }
}

方法3:用ReentrantLock

@Slf4j(topic = "ch.XianChengTongBuTest03")
public class XianChengTongBuTest03 {
    static ReentrantLock lock = new ReentrantLock();
    static boolean t2Run = false;
    static Condition t2Ready = lock.newCondition();
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            lock.lock();
            while (!t2Run) {
                log.debug("t2还没好");
                try {
                    t2Ready.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            lock.unlock();
            log.debug("1");
        }, "t1");
        Thread t2 = new Thread(() -> {
            log.debug("2");
            t2Run = true;
            lock.lock();
            t2Ready.signal();
            lock.unlock();
        }, "t2");
        t1.start();
        t2.start();
    }
}

假如有另外一个需求,是要有三个线程分别打印abc,三个线程循环打印abc五次,最后会有一个结果abcabcabcabcabc,试着去实现
实现1:利用wait-notifyAll去实现

public class TongBuTest01 {
    public static void main(String[] args) {
        WaitNotify wn = new WaitNotify(1, 5);
        new Thread(() -> {
            wn.print("a", 1, 2);
        }, "1").start();
        new Thread(() -> {
            wn.print("b", 2, 3);
        }, "2").start();
        new Thread(() -> {
            wn.print("c", 3, 1);
        }, "3").start();
    }
}

class WaitNotify {
    private int flag;
    private int loopNumber;

    public WaitNotify(int flag, int loopNumber) {
        this.flag = flag;
        this.loopNumber = loopNumber;
    }

    /**
     * @param str      打印字符串
     * @param waitFlag 关于本次输出的标记
     * @param nextFlag 关于下次输出的标记
     */
    public void print(String str, int waitFlag, int nextFlag) {
        for (int i = 0; i < loopNumber; i++) {
            synchronized (this) {
                while (flag != waitFlag) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print(str);
                flag = nextFlag;
                this.notifyAll();
            }
        }
    }
}

实现2:利用ReentrantLock去实现

//使用ReentrantLock解决
public class TongBuTest02 {
    public static void main(String[] args) throws InterruptedException {
        MyReentrantLock lock = new MyReentrantLock(5);
        Condition c1 = lock.newCondition();
        Condition c2 = lock.newCondition();
        Condition c3 = lock.newCondition();
        Thread t1 = new Thread(() -> {
            lock.print("a", c1, c2);
        }, "1");
        Thread t2 = new Thread(() -> {
            lock.print("b", c2, c3);
        }, "2");
        Thread t3 = new Thread(() -> {
            lock.print("c", c3, c1);
        }, "3");
        t1.start();
        t2.start();
        t3.start();
        Thread.sleep(1000);
        lock.lock();
        try {
            c1.signal();
        } finally {
            lock.unlock();
        }
    }
}

class MyReentrantLock extends ReentrantLock {
    private int loopNumber;

    public MyReentrantLock(int loopNumber) {
        this.loopNumber = loopNumber;
    }

    public void print(String str, Condition current, Condition next) {
        for (int i = 0; i < loopNumber; i++) {
            lock();
            try {
                current.await();
                System.out.print(str);
                next.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                unlock();
            }
        }
    }
}

实现3:利用parkUnpark去实现:

//利用park和unpark解决同步问题
public class TongBuTest03 {
    static Thread t1;
    static Thread t2;
    static Thread t3;
    public static void main(String[] args) throws InterruptedException {
        ParkUnpark parkUnpark = new ParkUnpark(5);
        t1 = new Thread(() -> {
            parkUnpark.print("a",t2);
        }, "t1");
        t2 = new Thread(() -> {
            parkUnpark.print("b",t3);
        }, "t1");
        t3 = new Thread(() -> {
            parkUnpark.print("c",t1);
        }, "t1");
        t1.start();
        t2.start();
        t3.start();
        Thread.sleep(1000);
        LockSupport.unpark(t1);
    }
}

class ParkUnpark {
    private int loopNumber;

    public ParkUnpark(int loopNumber) {
        this.loopNumber = loopNumber;
    }

    public void print(String str, Thread next) {
        for (int i = 0; i < loopNumber; i++) {
            LockSupport.park();
            System.out.print(str);
            LockSupport.unpark(next);
        }
    }
}
posted @   理塘DJ  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示