38. [Java]多线程

38.1. 创建

  • 使用Thread类开发多线程程序的步骤:

    1. 自定义一个子类,继承Thread

    2. 在子类中,重写run()方法(run方法中书写的是线程要执行的任务代码)
      Thread类中包含了创建并执行多线程的功能方法+线程要执行的任务(耦合度过高)

    3. 创建一个子类对象

    4. 通过子类对象调用.start() 开启一个新线程并执行

  • 使用Runnable接口开发多线程的步骤:

    1. 自定义一个实现Runnable接口的子类

    2. 在子类重写run方法

    3. 创建一个子类对象,并把该对象作为参数传递给Thread对象

    4. 创建一个Thread对象,并把实现Runnable接口的子类对象作为参数

    5. 调用Thread对象中的start方法

  • 使用Runnable接口比Thread类的优点:

    • 适合多个程序实现共享同一份资源

    • 实现了解耦

    • 避免Java中的单继承

  • 实现Callable接口来创建线程:

    1. 自定义一个子类实现Callable

    2. 在子类中重写call方法

    3. 创建线程池

    4. 创建Callable子类对象

    5. 把Callable对象作为参数传递给线程池

38.2. 线程安全

  • 发生原因:

    • 安全问题都是由全局变量及静态变量造成的

    • 多个线程同时对一个共享数据进行访问(在访问的同时存在修改操作),由于CPU切换不同的线程可能存在: A线程进行了修改,B线程却使用了修改前的数据

    • 解决方案:

      • 本质:把多线程变成单线程

      • 引入线程同步机制

        • 同步代码块

          • 针对run方法中的代码,使用synchronized关键字,把部分代码添加同步机制

            • 同步机制:在同一个而时间,只能有一个线程执行

              • 原理:线程在执行之前先获取到一个锁,然后开始执行线程任务,只有拿到锁的线程执行完包含在synchronized代码块中的内容之后,才会释放锁,才可以让其他线程拿到这个锁

            • 同步机制,关键是实现利用:锁(对象锁)

              • 锁: 对象锁。任何对象都可以当锁使用

                • String lock = new String()

                • Object lock = new Object()

        • 同步方法

          • 针对方法进行同步,同步方法只能用在方法上

          • 格式:public synchronized void method(){…}

          • 同步方法中的锁:

            • 非静态方法:锁是this(锁,当前对象)

            • 静态方法:静态方法没有对象的概念。所示Class(锁,类名.class)

        • 锁机制

38.3. 线程的生命周期

从线程的创建开始,一直到线程的销毁,整个过程称为:生命周期

  • 划分:

    • 创建 start() 线程创建成功

    • 就绪

    • 运行

    • 死亡

38.4. 线程控制

  • 控制方法:

    • sleep() 当前执行的线程进入睡眠状态

    • join() 等待当前线程死亡,当前线程必须执行完才能执行其他线程

    • setDeamon() 设置当前线程为和守护线程,特点:当没有普通线程在执行时,守护线程也停止运行

38.5. Loock锁