多线程并发保证线程的顺序执行

多线程并发保证线程的顺序执行
考虑为什么在并发的情况下要保证线程的并发执行
考虑到可能有如下几种情况
1.单纯面试 现场顺序执行的考点就是线程间的通信问题
2.真正的业务需求,如解析XML 我们想并发执行xml下多个节点,但是我们需要解析完成后再继续下不操作,如果节点中有依赖关系那我们就必须要保证一些顺序执行。

一.单纯面试来说 可实现的方式

1.join关键字

关键代码

        Thread t3 = new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"==开始执行");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }    
            System.out.println(Thread.currentThread().getName()+"==结束执行");
        },"t3");
        t1.start();
        t1.join();
        t2.start();
        t2.join();
        t3.start();
        t3.join();
        System.out.println("所有线程到此执行完毕");

输出结果

t1==开始执行
t1==结束执行
t2==开始执行
t2==结束执行
t3==开始执行
t3==结束执行
所有线程到此执行完毕

为什么join关键字能保证线程顺序执行那

我们看join方法的简介

    * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.

关键代码

   if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }

会发现如果这个线程是活着的话会用while循环阻塞 主线程的运行,来次达到线程顺序执行

2.Executor.newSimpleThreadPool

关键代码

        Thread t3 = new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"=t3=开始执行");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }    
            System.out.println(Thread.currentThread().getName()+"=t3=结束执行");
        },"t3");
        
        ExecutorService es = Executors.newSingleThreadExecutor();
        es.execute(t1);
        es.execute(t2);
        es.execute(t3);
        if(es.isShutdown())
        es.shutdown();
        System.out.println("所有线程到此执行完毕");

执行结果

所有线程到此执行完毕
pool-1-thread-1=t1=开始执行
pool-1-thread-1=t1=结束执行
pool-1-thread-1=t2=开始执行
pool-1-thread-1=t2=结束执行
pool-1-thread-1=t3=开始执行
pool-1-thread-1=t3=结束执行
可以看到 用SimlpPool的话 能保证线程顺序执行,且不阻塞主线程运行

我们可以看SimlpPool 方线程的是LinkedBlockingQueue 链表阻塞队列且容量只为1,而链表是阻塞所有保证线程先进先出的规则来执行

3.Lock下conditional

volatile static int  num = 1;

Lock lock = new ReentrantLock();
        Condition c1 = lock.newCondition();
        Condition c2 = lock.newCondition();
        Condition c3 = lock.newCondition();
        
        Thread t1 = new Thread(()->{
            lock.lock();
            try {
                while(num!=1) {
                    c1.await();
                }
                System.out.println(Thread.currentThread().getName()+"==开始执行");
                TimeUnit.SECONDS.sleep(1);
                 num = 2;
                c2.signal();
                System.out.println(Thread.currentThread().getName()+"==结束执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
            
        },"t1");

利用lock Condition num 阻塞的方式 实现 线程大顺序执行

我们看下Condition 说明

    * <p>Before waiting on the condition the lock must be held by the
     * current thread.
     * A call to {@link Condition#await()} will atomically release the lock
     * before waiting and re-acquire the lock before the wait returns.

在等待条件之前,锁由当前线程持有。调用wait()在等待和重新获得锁之前自动释放锁。

二 对于业务中我们可以考虑Callable接口

    public static void test4() throws InterruptedException, ExecutionException {
      Future<String> futA = new FutureTask<String>(new Sub1("A", null));
      Thread t1 = new Thread((Runnable) futA);
      t1.start();
      System.out.println(futA.get());
      
      Future<String> futB = new FutureTask<String>(new Sub1("B", null));
      Thread t2 = new Thread((Runnable) futB);
      t2.start();
      System.out.println(futB.get());
      
      Future<String> futC = new FutureTask<String>(new Sub1("C", null));
      Thread t3 = new Thread((Runnable) futC);
      t3.start();
      System.out.println(futC.get());
      System.out.println("程序结束");
    }
}
class Sub1 implements Callable<String> {

    private String str ;
    private Map<String, String> map ;
    
    public Sub1() {};
    public Sub1(String str,Map<String, String> map) {
        this.str = str;
        this.map = map ;
    };

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值