• Java面试_并发编程_线程基础


    线程基础

    线程和进程的区别(出现频率: 3⭐)

    • 进程是正在运行程序的实例, 进程中包含了线程, 每个线程执行不同的任务
    • 不同的进程使用不同的内存空间, 在当前进程下的所有线程可以共享内存空间
    • 线程更轻量, 线程上下文切换成本一般上要比进程上下文切换低(上下文切换指的是从一个线程切换到另一个线程)

    并行和并发的区别(出现频率: 2⭐)

    • 并发是单个CPU同时执行多个线程
    • 并行是多个CPU同时执行多个线程

    在这里插入图片描述

    线程的创建(出现频率: 4⭐)

    创建线程的方式

    • 继承Thread类
    • 实现runnable接口
    • 实现callable接口
    • 线程池创建线程(项目中使用方式)

    runnable和callable有什么区别

    • Runnable接口的run方法没有返回值
    • Callable接口的call方法有返回值, 需要FutureTask获取结果
    • Callable接口的call方法允许抛出异常; 而Runnable接口的run方法的异常只能在内部消化, 不能继续上抛

    run()和start()有什么区别

    • start(): 用来启动线程, 通过该线程调用run方法中所定义的逻辑代码. start方法只能被调用一次
    • run(): 正常调用方法, 封装了要被线程执行的代码, 可以被调用多次

    线程的状态(出现频率: 4⭐)

    线程的状态

    • 新建(new)
    • 可运行(runnable)
    • 阻塞(blocked)
    • 等待(waiting)
    • 时间等待(timed_waiting)
    • 终止(terminated)

    线程状态之间的变化

    • 创建线程对象是新建状态
    • 调用了start()方法变为可执行状态
    • 线程获取到了CPU的执行权, 执行结束是终止状态
    • 在可执行状态的过程中, 如果没有获取CPU的执行权, 可能会切换为其他状态
      • 如果没有获取锁(synchronized或lock)进入阻塞状态, 获得锁再切换为可执行状态
      • 如果线程调用了wait()方法进入等待状态, 其他线程调用notify()唤醒后可切换为可执行状态
      • 如果线程调用了sleep()方法, 进入计时等待状态, 到时间后可切换为可执行状态

    让线程按顺序执行(出现频率: 3⭐)

    使用join()方法

    public class JoinTest {
        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                System.out.println("t1");
            });
            Thread t2 = new Thread(() -> {
                try {
                    // 当t1线程执行完毕后, 线程继续执行
                    t1.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("t2");
            });
            Thread t3 = new Thread(() -> {
                try {
                    // 当t2线程执行完毕后, 线程继续执行
                    t2.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("t3");
            });
            t1.start();
            t2.start();
            t3.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

    notify()和notifyAll()有什么区别(出现频率: 2⭐)

    • notifyAll(): 唤醒所有wait的线程
    • notify(): 随机唤醒一个wait的线程
    public class notifyAndNotifyAllTest {
        static Object lock = new Object();
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(() -> {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + "...waiting...");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(Thread.currentThread().getName() + "...被唤醒了...");
                }
            }, "t1");
            Thread t2 = new Thread(() -> {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + "...waiting...");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(Thread.currentThread().getName() + "...被唤醒了...");
                }
            }, "t2");
    
            t1.start();
            t2.start();
    
            Thread.sleep(2000);
    
            synchronized (lock) {
                // lock.notify(); // 随机唤醒一个wait线程
                lock.notifyAll(); // 唤醒所有wait的线程
            }
        }
    }
    
    • 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

    wait方法和sleep方法的区别(出现频率: 3⭐)

    共同点

    • wait(), wait(long)和sleep(long)的效果都是让当前线程暂时放弃CPU的使用权, 进入阻塞状态

    不同点

    1. 方法归属不同
      • sleep(long)是Thread的静态方法
      • wait(), wait(long)都是Object的成员方法, 每个对象都有
    2. 醒来时机不同
      • 执行sleep(long)和wait(long)的线程都会在等待相应毫秒后醒来
      • wait(long)和wait()还可以被notify()唤醒, wait()如果不唤醒就一直等待
      • 他们都可以被打断唤醒
    3. 锁特性不同
      • wait方法的调用必须先获取wait对象的锁, 而sleep无此限制
      • wait方法执行后会释放对象锁, 允许其他线程获得该对象锁
      • sleep如果在synchronized代码块中执行, 并不会释放对象锁

    停止正在运行的线程(出现频率: 2⭐)

    • 使用退出标志, 是线程正常退出, 也就是当run方法完成后线程终止
      public class InterruptDemo extends Thread{
      
          volatile boolean flag = false; // 线程执行的退出标记
      
          @Override
          public void run() {
              while(!flag)
              {
                  System.out.println("MyThread...run...");
                  try {
                      Thread.sleep(3000);
                  } catch (InterruptedException e) {
                      throw new RuntimeException(e);
                  }
              }
          }
      
          public static void main(String[] args) throws InterruptedException {
      
              // 创建MyThread对象
              InterruptDemo t1 = new InterruptDemo();
              t1.start();
      
              // 主线程休眠6秒
              Thread.sleep(6000);
      
              // 更改标记为true
              t1.flag = true;
          }
      
      }
      
      • 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
    • 使用stop方法强行终止(不推荐, 方法已作废)
    • 使用interrupt方法中断线程
      • 打断阻塞的线程(sleep, wait, join)的线程, 线程会抛出InterruptedException异常
      • 打断正常的线程, 可以根据打断状态来标记是否退出线程
      public class InterruptDemo02 {
          public static void main(String[] args)      throws InterruptedException {
              // // 1. 打断阻塞的线程
              // Thread t1 = new Thread(() -> {
              //     System.out.println("t1正在运行...     ");
              //     try {
              //         Thread.sleep(5000);
              //     } catch (InterruptedException e) {
              //         throw new RuntimeException(e);
              //     }
              // }, "t1");
              // t1.start();
              // Thread.sleep(500);
              // t1.interrupt();
              // System.out.println(t1.isInterrupted     ());
      
              // 2. 打断阻塞的线程
              Thread t2 = new Thread(() -> {
                  while(true)
                  {
                      Thread current = Thread.     currentThread();
                      boolean interrupted = current.     isInterrupted();
                      if(interrupted){
                          System.out.println("打断状态     : "+interrupted);
                          break;
                      }
                  }
              }, "t2");
              t2.start();
              Thread.sleep(500);
              t2.interrupt();
              System.out.println(t2.isInterrupted());
          }
      }
      
      • 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

    来源

    黑马程序员. 新版Java面试专题视频教程
    小林coding. 图解系统-进程管理

    Gitee地址

    https://gitee.com/Y_cen/java-interview

  • 相关阅读:
    【接口测试】Jmeter接口实战-Dubbo接口+造10W数据测试(详细)
    Spring Cloud微服务治理框架深度解析
    洛谷P2456 二进制方程
    判断某一年的某个月的天数
    【C++】STL — vector的使用 + 模拟实现
    提高篇(八):扩展Processing功能:从库使用到跨平台应用
    【Python大数据笔记_day07_hive中的分区表、分桶表以及一些特殊类型】
    Spring Boot中全局异常处理器
    快速了解 Kubernetes 的架构及特性
    cookie 里面都包含什么属性?
  • 原文地址:https://blog.csdn.net/Y_cen/article/details/132975519