• Java-JUC(零):Java:现有线程T1/T2/T3,如何确保T1执行完成之后执行T2,T3在T2执行完成之后执行。


    要实现多个线程执行完成先后,就要知道如何实现线程之间的等待,java线程等待实现是join。java的jdk中join方法实现如下:

     1 public final synchronized void join(long millis)
     2     throws InterruptedException {
     3         long base = System.currentTimeMillis();
     4         long now = 0;
     5 
     6         if (millis < 0) {
     7             throw new IllegalArgumentException("timeout value is negative");
     8         }
     9 
    10         if (millis == 0) {
    11             while (isAlive()) {
    12                 wait(0);
    13             }
    14         } else {
    15             while (isAlive()) {
    16                 long delay = millis - now;
    17                 if (delay <= 0) {
    18                     break;
    19                 }
    20                 wait(delay);
    21                 now = System.currentTimeMillis() - base;
    22             }
    23         }
    24     }

    实现需求的方案一:

     1 public class TestMain {
     2     public static void main(String[] args) throws InterruptedException {
     3         Thread T1 = new MyThread("T1");
     4         Thread T2 = new MyThread("T2");
     5         Thread T3 = new MyThread("T3");
     6 
     7         System.out.println("T1 start.");
     8         T1.start();
     9         T1.join();
    10         System.out.println("T1 complete.");
    11 
    12         System.out.println("T2 start.");
    13         T2.start();
    14         T2.join();
    15         System.out.println("T2 complete.");
    16 
    17         System.out.println("T3 start.");
    18         T3.start();
    19         T3.join();
    20         System.out.println("T3 complete.");
    21     }
    22 }
    23 
    24 class MyThread extends Thread {
    25     public MyThread(String name) {
    26         setName(name);
    27     }
    28 
    29     @Override
    30     public void run() {
    31         for (int i = 0; i < 5; i++) {
    32             System.out.println(Thread.currentThread().getName() + ": " + i);
    33             try {
    34                 // do something...
    35                 Thread.sleep(100);
    36             } catch (InterruptedException e) {
    37                 e.printStackTrace();
    38             }
    39         }
    40     }
    41 }

    实现需求的方案二:

    public class Test2Main {
        public static void main(String[] args) {
            final Thread T1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("T1...");
                }
            });
            final Thread T2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        T1.join();
                    }catch (InterruptedException ex){
                        ex.printStackTrace();
                    }
                    System.out.println("T2...");
                }
            });
            final Thread T3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        T2.join();
                    }catch (InterruptedException ex){
                        ex.printStackTrace();
                    }
                    System.out.println("T3...");
                }
            });
    
            T3.start();
            T2.start();
            T1.start();
        }
    }

    实现方案三:使用ReentrantLock来解决, 还有个state整数用来判断轮到谁执行了

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ABC {
        private static Lock lock = new ReentrantLock();//通过JDK5中的锁来保证线程的访问的互斥
        private static int state = 0;
        
        static class ThreadA extends Thread {
            @Override
            public void run() {
                for (int i = 0; i < 10;) {
                    lock.lock();
                    if (state % 3 == 0) {
                        System.out.print("A");
                        state++;
                        i++;
                    }
                    lock.unlock();
                }
            }
        }
        
        static class ThreadB extends Thread {
            @Override
            public void run() {
                for (int i = 0; i < 10;) {
                    lock.lock();
                    if (state % 3 == 1) {
                        System.out.print("B");
                        state++;
                        i++;
                    }
                    lock.unlock();
                }
            }
        }
        
        static class ThreadC extends Thread {
            @Override
            public void run() {
                for (int i = 0; i < 10;) {
                    lock.lock();
                    if (state % 3 == 2) {
                        System.out.print("C");
                        state++;
                        i++;
                    }
                    lock.unlock();
                }
            }
        }
        
        public static void main(String[] args) {
            new ThreadA().start();
            new ThreadB().start();
            new ThreadC().start();
        }
        
    }

    使用lock来保证只有一个线程在输出操作, 要保证了state不会被两个线程同时修改, 思路简单

    实现方案四:还可以使用condition, condition的效率可能会更高一些, await会释放lock锁, condition的await和signal与object的wait和notify方法作用类似

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ABC2 {
        private static Lock lock = new ReentrantLock();
        private static int count = 0;
        private static Condition A = lock.newCondition();
        private static Condition B = lock.newCondition();
        private static Condition C = lock.newCondition();
        
        static class ThreadA extends Thread {
    
            @Override
            public void run() {
                lock.lock();
                try {
                    for (int i = 0; i < 10; i++) {
                        while (count % 3 != 0)
                            A.await(); // 会释放lock锁
                        System.out.print("A");
                        count++;
                        B.signal(); // 唤醒相应线程
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
            
        }
        
        static class ThreadB extends Thread {
    
            @Override
            public void run() {
                lock.lock();
                try {
                    for (int i = 0; i < 10; i++) {
                        while (count % 3 != 1)
                            B.await();
                        System.out.print("B");
                        count++;
                        C.signal();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
            
        }
        
        static class ThreadC extends Thread {
    
            @Override
            public void run() {
                lock.lock();
                try {
                    for (int i = 0; i < 10; i++) {
                        while (count % 3 != 2)
                            C.await();
                        System.out.println("C");
                        count++;
                        A.signal();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
            
        }
        
        public static void main(String[] args) throws InterruptedException {
            new ThreadA().start();
            new ThreadB().start();
            ThreadC threadC = new ThreadC();
            threadC.start();
            threadC.join();
            System.out.println(count);
        }
    }

    实现方案五:使用信号量也可以, 这个思路最简单, 整个代码也比较简洁

    import java.util.concurrent.Semaphore;
    
    public class ABC3 {
        private static Semaphore A = new Semaphore(1);
        private static Semaphore B = new Semaphore(1);
        private static Semaphore C = new Semaphore(1);
        
        static class ThreadA extends Thread {
    
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 10; i++) {
                        A.acquire();
                        System.out.print("A");
                        B.release();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
        }
        
        static class ThreadB extends Thread {
    
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 10; i++) {
                        B.acquire();
                        System.out.print("B");
                        C.release();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
        }
        
        static class ThreadC extends Thread {
    
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 10; i++) {
                        C.acquire();
                        System.out.println("C");
                        A.release();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
        }
        
        public static void main(String[] args) throws InterruptedException {
            B.acquire(); C.acquire(); // 开始只有A可以获取, BC都不可以获取, 保证了A最先执行
            new ThreadA().start();
            new ThreadB().start();
            new ThreadC().start();
        }
    }

    注意:

    lock是需要lock所有者去释放的, 即谁lock, 谁释放, 不可以跨线程, 会报java.lang.IllegalMonitorStateException;

    semaphore是没有所有者的说法, 可以跨线程释放和获取.

    方案三、四、五转自《[Java多线程]ABC三个线程顺序输出的问题

  • 相关阅读:
    二进制状态压缩对应 bool 数组中的常用操作
    [Acwing 327] 玉米田 题解
    [CF Contest] Web of Lies 题解
    ArchLinux安装vscode
    ArchLinux安装并且配置fcitx5
    【日常训练】取数问题
    Oracle sql 转 Hive sql一些语法问题
    Oracle中的connect by 转成hive的 lateral view explode
    Hive之分析函数
    数据仓库之拉链表设计
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/8784383.html
Copyright © 2020-2023  润新知