记一道多线程训练题目

30 篇文章 0 订阅

记给训练营师弟们的一道多线程题目

一、题目要求

			Task <Execute by Order>
	tips:
		1、开三个线程,这三个线程在一个死循环中不断创建,执行。每个打印的数字的不同。
		2、在不使用主线程休眠的情况下来保证三个线程的顺序不变。
		3、效率第一、不考虑空间复杂度。
		4、以下是问题代码模板:
		/**
		* @author linxu
		* @date 2019/7/17
		* <p>
		* 测试三个线程在无限执行下,都按照顺序打印1,2,3
		* </p>
		*/
public class Problem {
    public static void main(String[] args) throws Exception {
         Runnable p1 = () -> {
				//除了这句打印,其它可以修改
                System.out.println("1");
        };
        Runnable p2 = () -> {
         //除了这句打印,其它可以修改
               System.out.println("2");
        };
        Runnable p3 = () -> {
				//除了这句打印,其它可以修改
                System.out.println("3");
        };
        //keep the new order.avoid new asyn.
        while (true) {
		//这部分代码不允许修改
            Thread t1 = new Thread(p1);
            Thread t2 = new Thread(p2);
            Thread t3 = new Thread(p3);
            Thread.sleep(1000);
            //
            t1.start();
            t2.start();
            t3.start();
            Thread.sleep(1000);
            System.err.println("************************");
            Thread.sleep(1000);
        }

    }
}

二、解法一

  • 通过共享量
  //设置共享阈值
    private static int threashold = 0;

    public static void main(String[] args) throws Exception {
        Runnable p1 = () -> {
            while (threashold != 0) {
                //空自旋
            }
            //除了这句打印,其它可以修改
            System.out.println("1");
            threashold++;
        };
        Runnable p2 = () -> {
            while (threashold != 1) {
                //空自旋
            }
            //除了这句打印,其它可以修改
            System.out.println("2");
            threashold++;
        };
        Runnable p3 = () -> {
            while (threashold != 2) {
                //空自旋
            }
            //除了这句打印,其它可以修改
            System.out.println("3");
            threashold = 0;
        };
        //keep the new order.avoid new asyn.以下代码不准修改
        while (true) {
            //这部分代码不允许修改
            Thread t1 = new Thread(p1);
            Thread t2 = new Thread(p2);
            Thread t3 = new Thread(p3);
            Thread.sleep(1000);
            //尽可能保证同时启动
            t1.start();
            t2.start();
            t3.start();
            Thread.sleep(1000);
            System.err.println("************************");
            Thread.sleep(1000);
        }
    }
  • 以上采用了自旋思想,让线程都及时去检测共享变量的变化,从而当判断到是自己的标志,则执行,这样可以保证执行的有序,但是,慢!且占用CPU高。
    • 慢的原因:主要是在线程修改了共享变量,但是其它线程还未能够及时地知道共享变量的最新值
    • 解决方案:添加volatile,保证可见性
 //设置共享阈值
    private static volatile int threashold = 0;

三、解法二

解法一中,通过volatile修饰共享量,加速了线程对于共享量的更新,但是,从本质上,并没有多大的改变。解法二主要讲另外一种思想,即重入锁。

   static ReentrantLock lock = new ReentrantLock();
    static Condition firstCondition = lock.newCondition();
    static Condition secondCondition = lock.newCondition();
    static Condition thirdCondition = lock.newCondition();
    static int state = 1;

    public static void main(String[] args) throws Exception {
        Runnable p1 = () -> {
            lock.lock();
            try {
                if (state != 1) {
                    firstCondition.await();
                }
                System.out.println("1");
                secondCondition.signal();
                state = 2;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        };
        Runnable p2 = () -> {
            lock.lock();
            try {
                if (state != 2) {
                    secondCondition.await();
                }
                System.out.println("2");
                thirdCondition.signal();
                state = 3;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        };
        Runnable p3 = () -> {
            lock.lock();
            try {
                if (state != 3) {
                    thirdCondition.await();
                }
                System.out.println("3");
                firstCondition.signal();
                state = 1;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        };
        //keep the new order.avoid new asyn.
        while (true) {
            Thread t1 = new Thread(p1);
            Thread t2 = new Thread(p2);
            Thread t3 = new Thread(p3);
            Thread.sleep(1000);
            //
            t1.start();
            t2.start();
            t3.start();
            Thread.sleep(2000);
        }
    }
  • 好处
    • 避免不必要自旋,释放CPU占用粒度
    • 可重入锁,加速线程的执行
    • 顺序通知(P2P)每个执行片段,只有一个线程对另外一个线程的唤醒
  • 缺点
    • 占用多一小部分的内存
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值