• 线程同步


    join()

    线程加塞,它的作用是能够阻塞当前线程,等待执行了join()方法的线程执行完毕,再继续执行当前线程。

    public class JoinDemo {
        public void a(Thread joinThread) {
            System.out.println("a线程执行。。。");
            joinThread.start();
            try {
                joinThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("a线程执行完毕。。。");
        }
    
        public void b() {
            System.out.println("加塞线程执行。。。");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("加塞线程执行完毕。。。");
        }
    
        public static void main(String[] args) {
            JoinDemo joinDemo = new JoinDemo();
            Thread joinThread = new Thread(joinDemo::b);
            new Thread(() -> joinDemo.a(joinThread)).start();
        }
    }
    

    join()方法源码

    // 假设在主线程中执行了t.join()方法(t是一个线程对象)
    // 1. 需要弄明白一件事:谁拿了这个锁? 主线程拿了这个锁
    // 2. 这个锁是谁的? 是t线程的(t是一个对象,t对象的锁)
    // 3. 在这个方法中,当前的对象是t
    public final synchronized void join(long millis) throws InterruptedException {
            long base = System.currentTimeMillis();   // 获取当前的时间
            long now = 0;
    
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (millis == 0) {
                while (isAlive()) {   // 相当于this.isAlive(),它检测的是当前对象t线程是否处于活动状态
                    wait(0);   // 执行wait(0),这个wait()是让拿到锁的线程等待,也就是主线程
                }
            } else {
                while (isAlive()) {  // 同样检测t线程是否活动
                    long delay = millis - now;   // 延时多久
                    if (delay <= 0) {
                        break;
                    }
                    wait(delay);  // 等待延时的秒数
                    now = System.currentTimeMillis() - base;
                }
            }
        }
    

    java并发工具类

    本节主要讲的是juc包下的一些工具类

    CountDownLatch

    CountDownLatch是用于使一个线程等待其他线程各自执行完毕后再执行。

    使用实例:

    import java.util.concurrent.CountDownLatch;
    
    public class CountDownLatchDemo {
        public static void main(String[] args) throws InterruptedException {
            CountDownLatch countDownLatch = new CountDownLatch(10);   // 设置一个长度为10的计数器
    
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    try {
                        Thread.sleep((long) Math.random() * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + " 执行完毕");
                    countDownLatch.countDown();    // 每执行完一个线程 计数器减一
                }).start();
            }
            countDownLatch.await();   // 在这里阻塞等待其他线程执行完毕
            System.out.println("主线程执行完毕");
        }
    }
    

    CyclicBarrier

    这个类的作用是让一组线程互相等待,直到达到某个公共的点,才能继续往下执行。

    import java.util.Random;
    import java.util.concurrent.CyclicBarrier;
    
    public class CyclicBarrierDemo {
        public static void main(String[] args) {
            // 第二个参数是一个Runnable接口,用于所有线程到达后执行,交给最后一个到达的线程执行
            CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> System.out.println("好,人到齐了,现在开始开会"));
    
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    try {
                        Thread.sleep(new Random().nextInt(4000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    System.out.println(Thread.currentThread() + "到达了。。。");
                    // 在这里执行cyclicBarrier的等待,如果这里不能执行,程序就会一直卡住
                    try {
                        cyclicBarrier.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }
    

    Semaphore

    Semaphore实现的东西很简单,就是控制线程的并发数量,也就是同一时间只允许指定个数的线程运行

    import java.util.concurrent.Semaphore;
    
    public class SemaphoreDemo {
        public static void main(String[] args) {
            Semaphore semaphore = new Semaphore(10);  // 设置同一时间只允许10个线程执行
            while (true) {
                new Thread(() -> {
                    // 拿到许可
                    try {
                        semaphore.acquire();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 执行代码
                    System.out.println(Thread.currentThread() + " 执行了。。。");
                    // 释放许可
                    semaphore.release();
                }).start();
            }
        }
    }
    

    Exchanger

    用于两个线程之间交换数据, 只能是两个线程,他不支持更多的线程之间互换数据。

    import java.util.concurrent.Exchanger;
    
    public class ExchangerDemo {
        public static void main(String[] args) {
            Exchanger<String> exchanger = new Exchanger<>();
    
            new Thread(() -> {
                System.out.println("a开始抓取数据。。。");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String res = "123456";
                // 将数据交换
                try {
                    // 将自己的数据交换出去,并且拿到另一个线程交换过来的数据
                    String value = exchanger.exchange(res);
                    System.out.println("a比对结果:" + value.equals(res));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
    
            new Thread(() -> {
                System.out.println("b开始抓取数据。。。");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String res = "12345";
                // 将数据交换
                try {
                    String value = exchanger.exchange(res);
                    System.out.println("b比对结果:" + value.equals(res));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
    

    在上面的代码中,第一个线程采集数据用了1秒,第二个线程采集数据用了2秒,那么按理说,在执行exchange()方法交换数据的时候只有第二个线程才能拿到数据,因为第一个线程执行exchange()方法的时候第二个线程还在采集数据,理应拿不到数据。可是结果是它们都拿到了数据,那么说明在执行exchange()方法后会进行等待,一直到两个线程都到达同一个点了才会交换数据。

  • 相关阅读:
    关于32位操作系统和64位操作系统对InstallShield打包的影响
    NEWS: Symantec宣布Wise Package Studio将终止
    InstallShield 2012新功能试用(2) 调用MsiGetProperty等MSI API发生变化
    Basic INFO 在命令行Build InstallShield安装包工程获得压缩安装包
    NEWS InstallShield 2012 Service Pack 1发布
    Basic INFO InstallShield Basic MSI工程中如何在SetupCompleteSuccess界面中启动Readme
    Basic INFO InstallShield的脚本编辑器中如何显示代码行号
    Basic INFO 关于在InstallShield制作的安装包界面中删除InstallShield文字的厂商回复
    Basic INFO InstallShield工程中如何让产品的快捷方式名称始终与产品名保持一致
    Basic INFO: 创建隐藏文件夹
  • 原文地址:https://www.cnblogs.com/Myarticles/p/12046053.html
Copyright © 2020-2023  润新知