首页 > 其他分享 >控制多个线程的执行顺序

控制多个线程的执行顺序

时间:2022-12-03 12:45:21浏览次数:50  
标签:顺序 Thread 多个 lock t2 t1 线程 new

记录了如何控制多个线程的执行顺序,以练习题的形式记录

一、两个线程顺序执行

题目描述:

线程t1会打印A,线程t2会打印B,实现先打印B再打印A

题目分析:

实现的关键是线程1执行的时候要确定线程2已经执行过了,如果线程2还没执行就让线程1继续等待

wait notify 解法

public class Test7 {

    private static final Logger LOGGER = LoggerFactory.getLogger(Test7.class);

    private static boolean t2IsRun;
    private static Object lock = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    //t2还没执行前让t1 先wait
                    while (!t2IsRun){
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    //t2执行完了
                    LOGGER.info("A");
                }
            }
        },"t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    LOGGER.info("B");
                    //通知t1可以执行了
                    t2IsRun=true;
                    lock.notifyAll();
                }
            }
        },"t2");
        t1.start();
        t2.start();
    }
}

当然这里的lock对象可以换成ReentrantLock,这样就不用使用synchronized,可以在ReentrantLock的条件变量

Condition上进行等待,使用await和signal方法控制,道理是一样的。

Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // t2还没执行前让t1 先wait
                lock.lock();
                try {
                    while (!t2IsRun) {
                        try {
                            condition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            return;
                        }
                    }
                } finally {
                    lock.unlock();
                }

                //t2执行完了
                LOGGER.info("A");
            }
        }, "t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    LOGGER.info("B");
                    //通知t1可以执行了
                    t2IsRun = true;
                    condition.signal();
                } finally {
                    lock.unlock();
                }
            }
        }, "t2");
        t1.start();
        t2.start();

park unpark解法

private static final Logger LOGGER = LoggerFactory.getLogger(Test7.class);

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // t2还没执行前让t1先暂停
                LockSupport.park();
                //t2执行完了
                LOGGER.info("A");
            }
        }, "t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOGGER.info("B");
                //通知t1可以执行了
                LockSupport.unpark(t1);
            }
        }, "t2");
        t1.start();
        t2.start();
    }

这种解法里利用了park unpark方法的特性,

如果t1先执行park方法,线程t1会暂停执行,进入Waiting状态,当t2执行了unpark方法后t1恢复执行进入Runnable状态。

如果t2先执行unpark方法t1后边再执行park方法,则t1执行park方法时不会进行等待,会继续执行。

这个原理可以用一个比喻来理解,线程里有一个存干粮的地方,而且只能存一份,默认是空的,没有干粮,

park方法就是用来检查当前有没有干粮,如果没有干粮,线程就会开始等待,啥时候干粮来了就把干粮吃掉然后继续向下执行,注意这时候干粮槽又空了。如果当前有干粮,线程就会把干粮吃掉然后继续执行也就是不会等待。

unpark方法就是补充干粮,所以就会产生一种效果: 先执行的unpark可以让后执行的park方法不暂停。

二、三个线程交替执行

题目描述:

线程t1打印A,线程t2打印B,线程t3打印C,实现A,B,C这样的打印,然后循环10次

题目分析:

控制两个线程的先后可以使用布尔变量,控制三个线程的先后顺序可以使用int a变量来存储3中状态

a=1 t1运行,a=2 t2运行, a=3 t3运行,如果不满足条件就等待,t1运行完后让a=2,t2运行完让a=3,t3运行完让

a=1,这样就实现了交替

wait notify解法

public class Test7 {

    private static final Logger LOGGER = LoggerFactory.getLogger(Test7.class);

    private static final Object lock = new Object();
    private static int a=1;

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    //锁放在里边是在每一次循环的时候加锁,循环体执行完就释放锁,后边它如果抢到锁了就
                    //会开始下一轮循环,但是因为a的状态不对又会wait然后释放锁
                    
                    //注意锁加在for循环外边也是可以的,因为t1执行完会改变标记a,a的值改变后下次循环
                    //就会wait然后释放锁,这样别的线程就能抢到锁了
                    synchronized (lock){
                        while (a!=1) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                return;
                            }
                        }

                        LOGGER.info("A");
                        //改变标记 唤醒让下一个线程开始执行
                        a=2;
                        lock.notifyAll();
                    }
                }
            }
        },"t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    synchronized (lock){
                        while (a!=2){
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                return;
                            }
                        }

                        LOGGER.info("B");
                        //叫醒下一个线程
                        a=3;
                        lock.notifyAll();
                    }
                }
            }
        },"t2");

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    synchronized (lock){
                        while (a!=3){
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                        LOGGER.info("C");
                        a=1;
                        lock.notifyAll();
                    }
                }
            }
        },"t3");

        t1.start();
        t2.start();
        t3.start();
    }
}

await和signal 解法

public class Test7 {

    private static final Logger LOGGER = LoggerFactory.getLogger(Test7.class);

    private static final ReentrantLock lock = new ReentrantLock();

    private static  Condition condition1 =lock.newCondition();
    private static  Condition condition2 =lock.newCondition();
    private static  Condition condition3 =lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        //先wait
                        condition1.await();
                        LOGGER.info("A");
                        //叫醒下一个condition的线程
                        condition2.signal();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        return;
                    } finally {
                        lock.unlock();
                    }
                }
            }
        },"t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        condition2.await();
                        LOGGER.info("B");
                        //叫醒下一个condition的线程
                        condition3.signal();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        return;
                    } finally {
                        lock.unlock();
                    }
                }
            }
        },"t1");

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        condition3.await();
                        LOGGER.info("C");
                        //叫醒下一个condition的线程
                        condition1.signal();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        return;
                    } finally {
                        lock.unlock();
                    }
                }
            }
        },"t3");

        t1.start();
        t2.start();
        t3.start();
        //等待,确保三个线程都进入了等待
        Thread.sleep(1000);
        //主线程获取锁叫醒t1
        lock.lock();
        try {
            condition1.signal();
        } finally {
            lock.unlock();
        }
    }
}

准备三个Condition,一开始让三个线程都去condition等待,每个线程打印完后去唤醒下一个应该执行的线程,

等所有线程都运行后主线程中叫醒t1

park unpark解法

public class Test7 {

    private static final Logger LOGGER = LoggerFactory.getLogger(Test7.class);

    static Thread t1;
    static Thread t2;
    static Thread t3;

    public static void main(String[] args) throws InterruptedException {

        t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    LockSupport.park();
                    LOGGER.info("A");
                    LockSupport.unpark(t2);
                }
            }
        },"t1");

        t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    LockSupport.park();
                    LOGGER.info("B");
                    LockSupport.unpark(t3);
                }
            }
        },"t2");

        t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    LockSupport.park();
                    LOGGER.info("C");
                    LockSupport.unpark(t1);
                }
            }
        },"t3");

        t1.start();
        t2.start();
        t3.start();

        //利用unpark方法的特性,不用关是park先执行还是unpark先执行,叫醒t1
        LockSupport.unpark(t1);

    }
}

这种解法还是一开始让所有线程都暂停住,然后利用unpark方法的特性在主线程里让t1恢复执行

标签:顺序,Thread,多个,lock,t2,t1,线程,new
From: https://www.cnblogs.com/chengxuxiaoyuan/p/16947339.html

相关文章

  • Python笔记-多进程多线程
    日常运维中,经常需要并发来提升工作效率。Python提供了多线程和多进程两种方式。importtimeimportthreadingimportmultiprocessingdefprint_fun(num):print(time.str......
  • 添加线程组
    取样器错误后要执行的动作:继续,停止线程,停止测试线程数:可理解为当前线程组下脚本运行的“并发用户数”。Ramp­UpPeriod(inseconds):开始运行时线程数在“设定的时间”内......
  • 多线程
    静态代理各种内部类yieldjoin后是继续执行不是重新开始sleep的性质sleep不会释放锁?wait会每个线程都有自己的工作内存内存都是各自的互不影响是拷贝过去的......
  • SignalR 循序渐进(五)多个Hub服务器下的消息订阅
    SignalR的通讯方式决定了其高性能,但是即便如此,当消息的并发量上来以后,单节点的Hub服务器依然可能无法承载总的消息吞吐量,那么如何对Hub服务器做水平扩展呢?从微软官方的文......
  • 处理器从单核到多核的演化过程Linux-查看系统CPU个数、核心数、线程数
    Linux-查看系统CPU个数、核心数、线程数1.CPU个数(socket的个数)cat/proc/cpuinfo|grep"physicalid"|sort|uniq|wc-l2.每个CPU的核心数grep'coreid'/proc/cpuinfo......
  • 链接样式需要遵循LOHA顺序的原因
    《深入解析CSS》中有这样一句话伪类选择器(如:hover)和属性选择器(如[type="input"])与一个类选择器的优先级相同。通用选择器(*)和组合器(>、+、~)对优先级没有影响。也就是说对......
  • c++的线程安全静态检查 Thread Safety Analysis
    leveldb源码的过程中,发现很多成员变量被GUARDED_BY修饰,如下:structIterState{port::Mutex*constmu;Version*constversionGUARDED_BY(mu);MemTable*const......
  • 代码执行顺序
    先类加载AX然后main方法Y调用构造方法执行实例语句块输出C,(调用构造方法的时候实例语句块会先执行,再执行构造方法中的程序)然后BZ......
  • Python中mro继承顺序查询之C3算法
    1.mro遍历顺序1. python中存在多继承:A同时继承B和C,B继承E,C继承F,E和F最终继承object,如果我们访问A的实例对象的属性,他的查找方法遵循C3算法,(之前是深度优先查询,一条路......
  • vue多个方法的异步请求
    1、async和awaitasync/await是一种建立在Promise之上的编写异步或非阻塞代码的新方法。async是异步的意思,而await是asyncwait的简写,即异步等待。1//假设这是......