多线程

多线程

Rrocess 和Thread

  • 程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念
  • 而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位
  • 通常一个进程中有多个线程,当然一个进程最少有一个线程,不然没意义。线程是CPU调度和执行的单位
注意:很多线程是模拟出来的,真正的多线程是指多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就有同时执行的错觉

知识总结:

  • 线程就是独立的执行路径
  • 在程序运行是,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
  • main()称之为主线程,为系统的入口,用于执行整个程序
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预
  • 对同一份资源操作时,如cpu调度时间,,并发控制开销
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致想

Thread

  • 自定义线程类继承Thread类
  • 重写run方法,编写线程执行体
  • 创建线程对象,调用start方法启动线程

主线程和其他线程是并行执行

线程开启不一定立即执行,由CPU调度执行

小结

  • 继承Thread类

    子类继承Thread类具备多线程能力
    启动线程:子类对象.start()
    不建议使用:避免OOp单继承局限性
    
  • 实现Runnable接口

    实现接口Runnable具有多线程能力
    启动线程:传入目标对象 + Thread对象.start()
    推荐使用:避免OOP继承局限性,灵活方便,方便同一个对象被多个线程使用
    

Lamda表达式

函数式接口的定义:

  • 任何借口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
  • 对于函数式接口,我们可以通过lamda表达式来创建该接口的对象

总结:

lambda不大表达式只有一行代码情况下才能简化为一行,如果是多行,那么就用代码块来包装
必须是函数式接口
多个参数也可以,但是参数之间必须要加括号

同步方法

由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块

同步方法: public synchronized void method(int args){}

synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获取调用该方法的对象的锁,否则线程会阻塞,一旦方法执行,就独占该锁。直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行

缺陷:若将一个大的方法申明为synchronized将会影响效率

死锁

多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有”两个以上对象的锁“。就可能会发生“死锁”问题

产生死锁的四个条件:

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程已获得的资源,在未使用之前,不能进行强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

线程池

  • 背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大
  • 思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用
  • 好处:
    1. ​ 提高响应速度(减少了创建新线程的时间)
    2. 降低资源消耗(重复利用线程池中的线程,不需要每次创建)
    3. 便于线程管理
      • ​ corePoolSize:核心池的大小
      • maximumPoolSize:最大的线程数
      • keepAliveTime:线程没有任务时最多保持多长时间后会终止

线程池相关API:

​ ExecutorService 和 Executors

ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor

void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable
<T>Future<T>submit(Callable<T> task):执行任务,有返回值,一般又来执行Callable
void shutdown():关闭连接池

Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池