• Javase --- 多线程复习


    Java 多线程

    程序

    静态文件 程序 启动以后以 进程方式在 操作系统驻留

    进程 (可以看见)

    • 程序运行过程中 在操作系统内存中一个一个的实例。
    • 进程之间 独立存储 独立管理的 彼此是隔离的。
    • 程序 在 运行过程 中 至少有一个 进程与之对应 取决于 设计方式
    • 进程启动 默认 会启动一个 主线程(决定进程的生死 主线程死 进程死 主线程生 进程生)。

    总结 :

    • 程序 执行进入内存运行,变为一个进程
    • 进程间的资源(内存、文件····)是彼此隔离的,其他进程不允许访问(读取和写入)的。

    线程 (看不见)

    eg :

    • 迅雷 多线程下载软件

    概念 :

    • 线程 是 进程内的一个 “基本任务”,每个线程都有自己的功能, 是 CPU 分配和调度的基本单位
    • 一个进程内可以包含多个线程 , 一个线程只能隶属于一个进程
    • 进程内至少拥有一个 线程 这个线程叫做 主线程 主线程消亡 进程 结束。

    CPU、进程、线程

    单核 CPU

    时间片(cpu 一段的执行时间 以 纳秒 为单位)
    时间片 分配给 某个线程 ----> 某个线程 来执行
    这种情况 叫并发执行。

    多核
    • 一个线程 在同一时间 只能拥有一个 CPU 的时间片
    • 而 多个线程 在不同时间 可以 拥有不同 CPU 的时间片

    这就有了 并行 执行

    Java 中的 进程 与 线程

    Java 最简单程序的进程 包含 main 主线程 和 垃圾收集线程(没有关注你呢)

    线程创建的三种方式

    Thread (不推荐使用 Java 对 继承不友好)

    package nuc.zm.MoreThread.create_thread;
    
    import nuc.zm.io.ObjectIOTest.Object;
    
    /**
     * demo1
     * @description 创建线程的方式 1
     * @author zm
     * @date 2022/10/15
     */
    public class Demo1 {
    
    
        public static void main(String[] args) {
            TestThread testThread = new TestThread();
            for (int i = 0; i < 10; i++) {
                System.out.println("不会出现争夺资源的main" + i);
            }
            Thread thread = Thread.currentThread();
            thread.setName("主线程");
    //        让子线程先启动 才会出现 和主线程抢夺资源的情况hh
            testThread.setName("子线程");
            testThread.start();
    
            for (int i = 0; i < 10; i++) {
                System.out.println(thread.getName() + i);
            }
    
        }
    
          static class TestThread extends Thread {
              /**
               * 运行
               * 线程对象 争抢资源的任务 必须放在 run 方法中
               */
              @Override
              public void run() {
                  super.run();
                  for (int i = 0; i < 10; i++) {
                      System.out.println(getName()  + " ==== " + i);
                  }
              }
          }
    }
    
    
    • 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

    Runnable (Java编程友好 单无法返回执行后的数据)

    package nuc.zm.MoreThread.create_thread;
    
    /**
     * 以及接下来
     * 实现 Runnable 接口 成为线程类
     * @author zm
     * @date 2022/10/16
     */
    public class Demo2 implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "====" + i);
            }
        }
    
    //   main 线程 启动器
        public static void main(String[] args) {
            Demo2 demo2 = new Demo2();
            Thread thread = new Thread(demo2);
            thread.setName("子线程~~");
            thread.start();
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "========" + i);
            }
        }
    }
    
    
    • 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

    Callable (涉及到线程池 且线程方法具有返回值 但编程显复杂)

    package nuc.zm.MoreThread.create_thread;
    
    import java.util.Random;
    import java.util.concurrent.*;
    
    /**
     * 可调用测试
     *
     * @author zm
     * @date 2022/11/06
     */
    public class CallableTest {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            ThreadTest threadTest = new ThreadTest();
            threadTest.start();
        }
    
        static class ThreadTest implements Callable<Integer> {
            private String name;
    
            @Override
            public Integer call() throws Exception {
                int speed = new Random().nextInt(10);
                int result = 0;
                for (int i = 1; i < 10; i++) {
                    Thread.sleep(1000);
                    result = i * speed;
                    System.out.println("第 " + i + " 秒 " + this.name + " 已经跑到  " + result + " 米 " + " 速度 " + speed + " 米/秒 ");
                }
                return result;
            }
    
            public void start() throws ExecutionException, InterruptedException {
    //        线程池
                ExecutorService executorService = Executors.newFixedThreadPool(3);
                ThreadTest threadTest = new ThreadTest();
                threadTest.name = "参赛者A";
                ThreadTest threadTest1 = new ThreadTest();
                threadTest1.name = "参赛者B";
                ThreadTest threadTest2 = new ThreadTest();
                threadTest2.name = "参赛者C";
                Future<Integer> submit = executorService.submit(threadTest);
                Future<Integer> submit1 = executorService.submit(threadTest1);
                Future<Integer> submit2 = executorService.submit(threadTest2);
                executorService.shutdown();
                System.out.println(threadTest.name + "跑了" + submit.get() + "米");
                System.out.println(threadTest1.name + "跑了" + submit1.get() + "米");
                System.out.println(threadTest2.name + "跑了" + submit2.get() + "米");
    
            }
        }
    
    
    }
    
    
    • 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
    package nuc.zm.MoreThread.create_thread;
    
    import java.util.Random;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    /**
     * demo3
     * 实现 callable 接口
     * @author zm
     * @date 2022/10/16
     */
    public class Demo3 implements Callable<Double> {
        /**
         * 调用
         * 抛 子类 异常
         * @return {@link Double}
         */
        @Override
        public Double call() {
            return (double) new Random().nextInt(10);
        }
    
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            Demo3 demo3 = new Demo3();
            FutureTask<Double> futureTask = new FutureTask<>(demo3);
            Thread thread = new Thread(futureTask);
            thread.start();
            Object o = futureTask.get();
            System.out.println(o);
        }
    }
    
    
    • 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

    线程 同步问题

    现实案例 : 抛绣球案例 很多人争抢一个绣球(资源)

    synchronized(同步锁)

    作用 : 利用一个特定的对象设置一个锁 , 在 多线程 并发访问的时候,同时只允许一个线程 获得这个锁,并执行特定代码。
    执行后 会释放锁, 继续和其他线程争抢资源。

    所有线程都访问 同一个打印方法 就会出现 线程安全问题

    package nuc.zm.MoreThread;
    
    /**
     * 同步采样
     * 演示 同步锁
     * @author zm
     * @date 2022/11/06
     */
    public class SyncSample {
        static class Printer {
            public void print() {
                try {
                    Thread.sleep(500);
                    System.out.print("你");
                    Thread.sleep(500);
                    System.out.print("好");
                    Thread.sleep(500);
                    System.out.print("世");
                    Thread.sleep(500);
                    System.out.print("界");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
        }
        public void start() {
            Printer printer = new Printer();
            for (int i = 0; i < 10; i++) {
                PrintTask printTask = new PrintTask();
                printTask.printer = printer;
                Thread thread = new Thread(printTask);
                thread.start();
            }
    
        }
        static class PrintTask implements Runnable {
            private  Printer printer;
            @Override
            public void run() {
                printer.print();
            }
        }
        public static void main(String[] args) {
            new SyncSample().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

    解决 加锁

    synchronized 代码块 – 任意对象
    synchronized 方法 – this 当前对象
    synchronized 静态方法 – 该类的字节码对象

    package nuc.zm.MoreThread;
    
    import java.util.concurrent.locks.Lock;
    
    /**
     * 同步采样
     * 演示 同步锁
     * @author zm
     * @date 2022/11/06
     */
    public class SyncSample {
        static class Printer {
             public void print() {
                synchronized ("DADADADASDADAADADAD") {
                    try {
                        Thread.sleep(500);
                        System.out.print("你");
                        Thread.sleep(500);
                        System.out.print("好");
                        Thread.sleep(500);
                        System.out.print("世");
                        Thread.sleep(500);
                        System.out.print("界");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            public  synchronized  void print1() {
                    try {
                        Thread.sleep(500);
                        System.out.print("你");
                        Thread.sleep(500);
                        System.out.print("好");
                        Thread.sleep(500);
                        System.out.print("世");
                        Thread.sleep(500);
                        System.out.print("界");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            public  static synchronized  void print2() {
                try {
                    Thread.sleep(500);
                    System.out.print("你");
                    Thread.sleep(500);
                    System.out.print("好");
                    Thread.sleep(500);
                    System.out.print("世");
                    Thread.sleep(500);
                    System.out.print("界");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public void start() {
            Printer printer = new Printer();
            for (int i = 0; i < 10; i++) {
                PrintTask printTask = new PrintTask();
                printTask.printer = printer;
                Thread thread = new Thread(printTask);
                thread.start();
            }
    
        }
        static class PrintTask implements Runnable {
            private  Printer printer;
            @Override
            public void run() {
                    printer.print();
    //                printer.print1();
    //                Printer.print2();
            }
        }
        public static void main(String[] args) {
            new SyncSample().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
    • 79
    • 80
    • 81

    线程安全

    • 在 拥有 多条线程 并行执行的程序中,线程安全的代码 会通过同步机制保证各个线程可以正常 且正确的执行,不会出现数据污染的意外情况。

    线程池

    JUC 并发工具包 解决 同步 和 互斥问题
    • Runnable 新建 线程 , 性能差~~~
    • 线程 被频繁创建,相互竞争,严重时可能导致系统资源死机或者内存溢出
    • 线程池 ----- 线程复用
    • ThreadPool 线程池
      • 重用 存在的线程,减少线程对象的创建,消亡的开销
      • 线程总数可控,提高资源的利用率
      • 提供额外功能,定时执行,定期执行 和 监控。
    • 支持的线程池种类
      • 工具类 Executors(juc 包下) 创建线程池
      • FixedThreadPool - 定长线程池
      • CachedThreadPool - 可缓存的线程池
      • SingleThreadPool - 单线程池
      • ScheduledThreadPool - 调度线程池
  • 相关阅读:
    小程序线上调试优化
    Excel VSTO开发8 -相关控件
    element ui的动态校验的写法(变量动态校验,动态提示信息)与注意事项
    Redis链表
    彻底卸载Windows Defender
    【手写算法实现】 之 朴素贝叶斯 Naive Bayes 篇
    Vue 之 生命周期
    spring推断构造函数
    gson的工具类JsonUtils
    什么是客户体验 (CX)?如何改善客户体验?
  • 原文地址:https://blog.csdn.net/qq_53913402/article/details/127713641