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线程执行完毕");
    }

}

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

  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();
    }

三 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();
                }
            }

        }
    }

四 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();
        }
    }

}

五 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();
    }
}

六 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();
    }

}

七 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

    }
}

 

分类
收藏
回复
举报
回复
    相关推荐