Java控制线程顺序执行的常用方法汇总

hushuo
发布于 2021-3-24 11:18
浏览
0收藏

一,Jdk 线程的join()方法
按需要执行的顺序依次加入即可,简单也比较常用

public class Test {
    public static void main(String[] args) {
        Thread threadA = new Thread("A") {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.print("我是线程A执行");
            }
        };
        Thread threadB = new Thread("B") {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.print("我是线程B执行");
            }
        };
        Thread threadC = new Thread("C") {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.print("我是线程C执行");
            }
        };
        try {
            threadA.start();
            threadA.join();
            threadB.start();
            threadB.join();
            threadC.start();
            threadC.join();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.print("main线程执行完毕");
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.

二使用线程池创建单一的线程去实现

  ExecutorService service = Executors.newSingleThreadExecutor();
        service.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.print("runnable a 执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.print("runnable b 执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.print("runnable c 执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        service.shutdown();
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

三 object的 wait(),notify()方法,配合synchronized使用

public class Test3 {
    private static volatile int STEP = 0;

    public static void main(String[] args) {
        Step step = new Step();
        new Thread(new RunnableA(step)).start();
        new Thread(new RunnableB(step)).start();
        new Thread(new RunnableC(step)).start();
    }

    public static class RunnableA implements Runnable {
        private Step step;

        private RunnableA(Step step) {
            this.step = step;
        }

        @Override
        public void run() {
            step.excuteA();
        }
    }

    public static class RunnableB implements Runnable {
        private Step step;

        private RunnableB(Step step) {
            this.step = step;
        }

        @Override
        public void run() {
            step.excuteB();
        }
    }

    public static class RunnableC implements Runnable {
        private Step step;

        private RunnableC(Step step) {
            this.step = step;
        }

        @Override
        public void run() {
            step.excuteC();
        }
    }


    public static class Step {

        public void excuteA() {
            synchronized (this) {
                try {
                    System.out.println("线程A开始执行");
                    while (STEP != 0) { // 用while  if唤醒后会直接往下执行
                        System.out.println("STEP" + STEP);
                        wait();
                    }
                    Thread.sleep(3000);//模拟延迟//休眠不会释放锁 ,需要放到wait后面
                    STEP = 1;
                    System.out.println("线程A执行完毕");
                    notifyAll();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }

        public void excuteB() {
            synchronized (this) {
                try {
                    while (STEP != 1) {
                        wait();
                    }
                    System.out.println("线程B开始执行");
                    Thread.sleep(3000);
                    STEP = 2;
                    System.out.println("线程B执行完毕");
                    notifyAll();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }

        public void excuteC() {
            synchronized (this) {
                try {
                    while (STEP != 2) {
                        wait();
                    }
                    System.out.println("线程c开始执行");
                    Thread.sleep(3000);
                    System.out.println("线程C执行完毕");
                    notifyAll();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.

四 CountDownLatch
CountDownLatch是JAVA提供在并发包下的一个辅助类,可以把它看成是一个计数器,其内部维护着一个count计数,只不过对这个计数器的操作都是原子操作,同时只能有一个线程去操作这个计数器,CountDownLatch通过构造函数传入一个初始计数值,调用者可以通过调用CounDownLatch对象的cutDown()方法,来使计数减1;如果调用对象上的await()方法,那么调用者就会一直阻塞在这里,直到别人通过cutDown方法,将计数减到0,才可以继续执行。

public class Test4 {
    private static final int[] lock = new int[1];

    public static void main(String[] args) {
        final CountDownLatch countDownLatch = new CountDownLatch(3);
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    try {
                        while (countDownLatch.getCount() != 3) {
                            lock.wait();// 必须用锁对象的wait()
                        }
                        Thread.sleep(3000);//模拟延迟
                        System.out.println("线程A执行完毕");
                        countDownLatch.countDown();
                        lock.notifyAll();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    try {
                        while (countDownLatch.getCount() != 2) {
                            lock.wait();
                        }
                        Thread.sleep(3000);//模拟延迟
                        System.out.println("线程B执行完毕");
                        countDownLatch.countDown();
                        lock.notifyAll();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    try {
                        while (countDownLatch.getCount() != 1) {
                            lock.wait();
                        }
                        Thread.sleep(3000);//模拟延迟
                        System.out.println("线程C执行完毕");
                        countDownLatch.countDown();
                        lock.notifyAll();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        try {
            countDownLatch.await();
            System.out.print("main执行完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.

五 CyclicBarrier
栅栏类似于闭锁,它能阻塞一组线程直到某个事件的发生。栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。 CyclicBarrier可以使一定数量的线程反复地在栅栏位置处汇集。当线程到达栅栏位置时将调用await方法,这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达栅栏位置,那么栅栏将打开,此时所有的线程都将被释放,而栅栏将被重置以便下次使用。

public class Test5 {
    public static void main(String[] args) {
        final CyclicBarrier cyclicBarrier1 = new CyclicBarrier(2);
        final CyclicBarrier cyclicBarrier2 = new CyclicBarrier(2);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程A开始执行任务");
                    Thread.sleep(5000);
                    System.out.println("线程A执行完毕");
                    cyclicBarrier1.await();//阻塞等待所有的线程到达
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    cyclicBarrier1.await();//1号栅栏解除阻塞
                    System.out.println("线程B开始执行");
                    Thread.sleep(5000);
                    System.out.println("线程B执行完毕");
                    cyclicBarrier2.await();//2号阻塞等待所有的线程到达
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    cyclicBarrier2.await();//2号栅栏解除阻塞
                    System.out.println("线程c开始执行");
                    Thread.sleep(5000);
                    System.out.println("线程c执行完毕");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.

六 ReentrantLock
配合自定义执行条件 原理同wait() notify()

public class Test7 {
    private volatile static int step = 1;
    private static ReentrantLock lock = new ReentrantLock();

    final private static Condition conditionA = lock.newCondition();

    public static void main(String[] args) {

        Thread threadA = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (step != 1) {
                        conditionA.await();
                    }
                    System.out.println("A线程开始执行");
                    Thread.sleep(3000);
                    step = 2;
                    System.out.println("A线程执行完毕");
                    conditionA.signalAll();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };


        Thread threadB = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (step != 2) {
                        conditionA.await();
                    }

                    System.out.println("B线程开始执行");
                    Thread.sleep(3000);
                    step = 3;
                    System.out.println("B线程执行完毕");
                    conditionA.signalAll();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread threadC = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (step != 3) {
                        conditionA.await();
                    }
                    System.out.println("c线程开始执行");
                    Thread.sleep(3000);
                    step = 1;
                    System.out.println("c线程执行完毕");
                    conditionA.signalAll();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };
        threadA.start();
        threadB.start();
        threadC.start();
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.

七 synchronized
配合wait(),notify()+自定义执行条件,原理同上wait notify

八 Semaphore(信号量)
Semaphore 通常我们叫它信号量, 可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。

acquire()
获取一个令牌,在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态。

acquire(int permits)
获取一个令牌,在获取到令牌、或者被其他线程调用中断、或超时之前线程一直处于阻塞状态。

acquireUninterruptibly() 获取一个令牌,在获取到令牌之前线程一直处于阻塞状态(忽略中断)。

tryAcquire() 尝试获得令牌,返回获取令牌成功或失败,不阻塞线程。

tryAcquire(long timeout, TimeUnit unit) 尝试获得令牌,在超时时间内循环尝试获取,直到尝试获取成功或超时返回,不阻塞线程。

release() 释放一个令牌,唤醒一个获取令牌不成功的阻塞线程

public class Test6 {

    public static void main(String[] args) {
        final Semaphore semaphore1 = new Semaphore(0);//一开始就使线程阻塞从而让其他线程顺序执行。
        final Semaphore semaphore2 = new Semaphore(0);
        final Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    semaphore1.acquire();
                    System.out.println("线程B开始执行");
                    Thread.sleep(5000);
                    System.out.println("线程B执行完毕");
                    semaphore1.release();
                    semaphore2.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        final Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    semaphore2.acquire();//暂时无法获取 等待线程A执行完毕后释放 保证了线程执行顺序
                    System.out.println("线程c开始执行");
                    Thread.sleep(5000);
                    System.out.println("线程c执行完毕");
                    semaphore2.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程A开始执行");
                    Thread.sleep(5000);
                    System.out.println("线程A执行完毕");
                    thread2.start();//顺序执行B C
                    thread3.start();
                    semaphore1.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();//先执行线程A

    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.

 

分类
收藏
回复
举报


回复
    相关推荐