01 多线程 概念部分

目录

面试:进程和线程的区别

Java进程与线程的关系

面试: Thread中start与run方法的区别

面试: Thread和Runnable是什么关系?

面试: 如何给run方法传递参数?

面试: 如何处理线程的返回值?

线程的状态

New

Runnable

Waiting

Timed Waiting

Blocked

Terminated

面试: sleep和wait的区别

面试: notify和notifyAll的区别

yield

面试: 如何中断线程?


  1. 面试:进程和线程的区别

    1. 进程是资源分配的最小单位, 线程是CPU调度的最小单位
      1. 所有与进程有关的内容都被记录在PCB(进程控制块)中
    2. 进程独占内存空间, 保存各自的运行状态, 相互间不干扰且可相互切换, 为并发处理任务提供了可能
    3. 线程共享进程的内存资源, 相互间切换更快速, 支持更细粒度的任务控制, 使进程内的子任务得以并发执行
    4. 进程切换比线程切换开销大
    5. Java进程与线程的关系

      1. 每运行一个Java程序就会产生一个进程, 一个进程至少包含一个线程
      2. 一个进程对应一个jvm实例, 每一个jvm实例都有一个自己的堆, 多个线程共享进程的堆, 每个线程又都有自己的栈空间
      3. Java采用单线程编程模式, 程序会自动创建主线程
        1. 耗时的操作可以放到子线程中, 以避免阻塞主线程执行
      4. 主线程可以创建子线程, 原则上要后于子线程完成执行
      5. jvm实例除了创建主线程之外还会创建其他的线程, 例如垃圾回收线程
  2. 面试: Thread中start与run方法的区别

    1. 调用start方法会创建一个新的子线程并启动, 然后通过子线程去执行run方法
    2. 而run方法仅仅是Thread的一个普通方法调用而已, 里面放的是子线程任务的方法体, 如果你在main方法直接调用run方法, 那他也是会执行的, 但调用他的是主线程而不是子线程
  3. 面试: Thread和Runnable是什么关系?

    1. Runnable是一个接口, 里面只有一个run抽象方法
    2. Thread是一个类, 它实现了Runnable接口, 使run方法支持多线程
    3. 因为Java的单一继承原则, 为了提高程序的可扩展性, 推荐多使用Runnable接口
      1. 一个类只能由一个父类, 继承了Thread就没办法继承别的类了
    4. 使用Thread创建线程: 继承Thread类, 实现里面的run方法, 调用start方法即可.
    5. 使用Runnable创建线程: 创建Runnable接口的实现类, 重写里面的run方法, 创建Thread对象, 并把前面的实现类对象作为参数传递给Thread的构造方法, 调用Thread对象的start方法即可.
  4. 面试: 如何给run方法传递参数?

    1.  实现的方法主要有三种
      1. 使用构造函数传参
      2. 使用成员变量传参
        1. get/set
      3. 使用回调函数传参
  5. 面试: 如何处理线程的返回值?

    1. 实现的方法有三种
      1. 主线程等待法

        1. 让主线程使用while循环不断的去查询成员变量, 直到成员变量符合条件为止
        2. 缺点
          1. 当需要等待的线程多起来之后, 代码就会臃肿
          2. 循环一次的时间不好确定
      2. 使用Thread的join方法阻塞当前线程, 直到子线程执行完毕
        1. package demo08_join;
          
          /**
           * @author LQ
           * @create 2020-07-25 17:57
           */
          public class Demo01 implements Runnable {
              private static String value;
          
              @Override
              public void run() {
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  value = "qweqwe";
              }
          
              public static void main(String[] args) throws InterruptedException {
                  Thread thread = new Thread(new Demo01());
                  thread.start();
                  thread.join();
                  System.out.println("value = " + value);
              }
          }

           

        2. 优点: 实现起来简单, 不用自己去确定等待时间了
      3. 通过实现Callable接口
        1. 使用这种方法时依旧有两种子方法来获取返回值
          1. 通过使用FutureTesk对象获取返回值
            1. FutureTask继承了Future接口
            2. FutureTask有两个get方法
              1. 无参的方法是, 当子线程执行完毕后获取其返回值
              2. 带参的方法是, 等待指定的时间来获取其返回值, 超时即放弃
            3. 代码
              1. package demo09_callable;
                
                import java.util.concurrent.ExecutionException;
                import java.util.concurrent.FutureTask;
                
                /**
                 * @author LQ
                 * @create 2020-07-25 18:11
                 */
                public class Test01 {
                    public static void main(String[] args) throws ExecutionException, InterruptedException {
                        FutureTask<String> task = new FutureTask<>(new MyCallable());
                        Thread thread = new Thread(task);
                        thread.start();
                        if (!task.isDone()){
                            System.out.println("工作还没有完成!");
                        }
                        System.out.println("完成了"+task.get());
                        System.out.println("111");
                    }
                }

                 

          2. 通过线程池获取返回值
            1. 方法和FutureTask差不多
            2. 线程池的submit方法可以返回一个Future对象, 对象里面有get和isDone方法
            3. 代码
              1. package demo09_callable;
                
                import java.util.concurrent.ExecutionException;
                import java.util.concurrent.ExecutorService;
                import java.util.concurrent.Executors;
                import java.util.concurrent.Future;
                
                /**
                 * @author LQ
                 * @create 2020-07-25 18:28
                 */
                public class Test02_ThreadPool {
                    public static void main(String[] args) {
                        ExecutorService threadPool = Executors.newCachedThreadPool();// 创建线程池
                        Future<String> stringFuture = threadPool.submit(new MyCallable());// 提交线程任务, 返回的是一个Future
                        if (!stringFuture.isDone()) {
                            // 线程还没有执行完毕
                            System.out.println("任务还怎么完成~");
                        }
                        try {
                            System.out.println("任务完成了 " + stringFuture.get());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            e.printStackTrace();
                        } finally {
                            threadPool.shutdown();// 关闭线程池
                        }
                    }
                }

                 

        2. Callable接口
          1. 这个接口只有一个方法call, 它其实和run方法差不多, 都是给线程设置任务
          2. 实现了Callable接口的类
            1. package demo09_callable;
              
              import java.util.concurrent.Callable;
              
              /**
               * @author LQ
               * @create 2020-07-25 18:09
               */
              public class MyCallable implements Callable<String> {
                  @Override
                  public String call() throws Exception {
                      System.out.println("开始工作");
                      Thread.sleep(2000);
                      System.out.println("工作完成");
                      return "hello";
                  }
              }

               

  6. 线程的状态

    1. New

      1. 线程创建好了还没有启动时就是这个状态
    2. Runnable

      1. 线程创建好了调用了start方法会进入这个状态
      2. 这个状态有两个子状态Running  Ready
        1. Running: 线程正在使用cpu
        2. Ready: 线程可以运行, 正在等待cpu
    3. Waiting

      1. 不会被分配cpu资源, 需要其他线程去唤醒它
      2. 调用锁对象的wait方法和子线程的join方法都可使当前线程进入Waiting状态
    4. Timed Waiting

      1. 在等待一段时间后可以自动唤醒
      2. 使用sleep方法或者带参数的wait和join方法可以使线程进入这个状态
    5. Blocked

      1. 等待获取排它锁时会进入这个状态
      2. 这个线程是可以运行的, 但是当轮到他使用cpu时发现锁对象被别的线程占用着, 这个线程就会被阻塞住
    6. Terminated

      1. 线程执行完毕
      2. 线程执行完毕后再次调用start方法会报错
  7. 面试: sleep和wait的区别

    1. sleep是Thread类的方法, wait是Object类的方法
    2. sleep()方法可以在任何地方使用, wait()方法只能在同步代码块或同步方法中使用
      1. 因为wait()会释放锁, 既然你要释放锁, 那么你就要在同步代码块或同步方法中, 因为只有他俩才有锁
    3. sleep()方法只会让出cpu资源, 不会改变锁的状态, wait()不仅会让出cpu也会释放锁
      1. 如果在同步代码块中调用了sleep方法, 那么在sleep的时间还没有结束的时候是不会释放锁的
  8. 面试: notify和notifyAll的区别

    1. 先来了解一下锁池(EntryList)等待池(WaitSet)
      1. 锁池: 没有获取到锁被阻塞的线程会进入锁池
        1. 线程获取锁是根据线程的优先级, 所以使用EntryList
      2. 等待池: 线程A调用了锁对象的wait方法, 线程A释放该锁对象, 并进入该锁对象的等待池中
        1. 唤醒等待池中的线程是随机的, 所以使用WaitSet
    2. 唤醒的线程会进入到锁池中去竞争锁
    3. notifyAll会让所有在等待池中的线程进入锁池中去竞争锁
    4. notify会随机选取一个等待池中的线程进入锁池
    5. wait notify notifyAll 只能在同步方法or同步代码块中使用, 否则会报IllegalMonitorStateException(非法监测状态异常)
  9. yield

    1. 调用静态方法Thread.yield()即声明当前线程已经完成了其生命周期中的重要部分了, 可以将CPU让出切换到其他的线程了
    2. 该方法只是一个建议, 具体是否切换还是要看线程调度器, 而且也只是建议其他相同优先级的线程可以执行
  10. 面试: 如何中断线程?

    1. 已经被抛弃的方法
      1. 通过线程对象的stop()中断线程
      2. 这种方法是不安全的, 一个线程使用stop方法去终止另外一个线程, 它并不知道另一个线程是什么状态, 有可能一些清理工作还没有完成
    2. 目前使用的方法
      1. interrupt(): 通知线程应该中断了
      2. 调用interrupt方法后, 被中断的线程会有下面两种情况
        1. 如果线程正处在阻塞状态(join) or 计时等待(sleep) or 无限等待(wait), 那么线程会立即退出被阻塞状态, 并抛出一个InterruptedException异常, 从而提前结束该进程. 但是不能中断I/O阻塞和synchronized锁阻塞
          1. 线程正常运行完毕会结束, 线程抛出异常也会结束
        2. 如果线程处在正常运行状态, 那么会将线程的中断标志位置为true. 被中断的线程正常运行, 如果需要中断的话只需要不断的监听当前线程的中断标志位即可
          1. 使用线程对象的isInterrupted()方法获取线程的中断标志位
          2. 使用线程对象的interrupted()方法也行
      3. Executor的中断操作
        1. 调用 Executor 的 shutdown() 方法会等待线程都执行完毕之后再关闭,但是如果调用的是 shutdownNow() 方法,则相当于调用每个线程的 interrupt() 方法
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值