多线程与锁

进程与线程

进程 进程是程序执行的一次过程,是系统运行程序的基本单位,进程是动态的.系统运行一个程序就代表一个进程生命周期从创建,运行到消亡的过程。

    在java中,启动main函数就代表启动了一个jvm的进行.main函数所在的线程就是这个进程中的一个线程,也称主线程.

线程 线程和进程相似,但是线程是比进程更小的执行单元.一个进程在执行的过程中会产生多个线程.与线程不同的是同类的多个线程之间会共享进行的堆空间和方法区中的资源,并且每个线程都有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间进行上下文切换时,负担是要比进程小得多的,因此线程也被称为轻量级进程.

线程与进程的关系,区别及优缺点 一个进程可以有多个线程,多个线程共享进程的堆空间和方法区(jdk8以后被称为元空间)资源,但是每个线程都有自己的程序计数器,虚拟机栈和本地方法栈.

    线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。线程执行开销小,但不利于资源的管理和保护;而进程正相反。

线程的创建方式

1、继承Thread类

2、实现Runable接口

3、实现Callable接口

4、 线程池

线程池工作流程

当线程池有任务提交时,首先会先进行判断是否超过了核心线程数,如果没有超过,则会创建对应的工作线程来执行任务。如果超过的话会将新提交的任务存放入工作队列中,等待核心线程任务执行完成后,再去执行。如果工作队列已满的话,则会根据线程的最大数量来创建对应的临时线程,来执行任务。如果超过了线程池的最大数量,则会执行拒绝策略来处理这个任务。

线程池核心参数

  • 核心线程数

  • 最大线程数

  • 线程保活时间

  • 阻塞队列

  • 临时线程保活时间单位

  • 线程工厂

  • 拒绝策略

    四种拒绝策略

  1. 拒绝任务并丢出异常(默认)

  2. 丢弃任务,但是不抛出异常。

  3. 丢弃队列中最前面的任务,然后重新提交被拒绝的任务

  4. 调用主线程来执行该任务

    参数设置

    CPU密集型:corePoolSize = CPU核数 + 1

    IO密集型:corePoolSize = CPU核数 * 2

面试

线程池创建了,里面有线程吗?
没有,任务提交过来,创建线程去执行
如果到达了最大线程数,请问,这个核心线程是多少?
核心线程数就是最大线程数
继承Thread类和实现Runnable接口,有什么区别?你一般选择哪个?为什么?
一般选择Runnable,因为thred底层也是实现了Runnable接口,选择Runnable的话更符合接口隔离原则,单一原则及开闭原则

线程的生命周期

新建、就绪、运行、阻塞、死亡

执行流程

一个线程的创建首先是调用start启动方法,代表一个线程出生了之后线程进入就绪的状态,在这个时候线程会获得CPU的执行权从而进入到运行状态,但是在运行状态中可能会进入阻塞状态(sleep,join),阻塞等待状态(wait),阻塞锁定状态(lock,synchronized)其中在线程等待状态下也可能会进入线程阻塞锁定状态.当阻塞结束后会重新回到就绪状态,此时有继续抢夺CPU的执行权,其中在运行状态中调用yield方法也会重新会到就行状态,线程运行结束或者抛出异常后就会进入结束状态

线程安全问题

Synchronized 与 Lock 的区别?
Synchronized

存在层次 JVM层面\是关键字

锁的释放 只有当线程执行完毕后或出现异常时才会释放锁,不会出现死锁

锁的获取 只有当前一个线程释放资源后才能拿到锁

锁状态 无法判断锁的状态

锁类型 可重入 不可中断 非公平

性能 少量同步

Lock

存在层次 Api层面,是一个接口

锁的释放 必须要在finally中释放锁,否则将会出现死锁的情况

锁的获取 lock锁有多个获取锁的方式,不需要线程一直等待

锁状态 可以判断锁的状态

锁类型 可重入 可判断 可公平

性能 大量同步

Synchronized

普通同步方法,锁是当前实例对象 this

静态同步方法,锁是当前类的class对象

底层实现原理是:通过javap命令来使用 monitorenter 和 monitorexit 指令实现的

锁分类

悲观锁与乐观锁

        悲观锁   : Synchronized Lock 数据库的行锁、表锁
        乐观锁   :   数据库使用version字段 
CAS

        CAS 的思想就是用一个预期值和要更新的变量值进行比较,两值相等才会进行更新。

        CAS 是一个原子操作,底层依赖于一条 CPU 的原子指令

公平锁与非公平锁

公平锁:按线程顺序获得锁

非公平锁:线程随机获得锁

死锁

1、系统资源不足;

2、进程运行推进的次序不合适;

3、资源分配不当。

4、如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

死锁产生的原因及四个必要条件

1、互斥条件:一个资源一次只能被一个进程访问。

2、请求与保持: 一个进程因请求资源而阻塞时,对已获得的资源保持不放。

3、不可剥夺:进程已获得的资源,在未使用完之前,不得强行剥夺。

4、循环等待:若干进程之间形成一种头尾相接的循环等待资源关系

线程通信

1、同步通信

例如 wait notify notifyAll

2、异步通信

消息中间件

3、进程间的通信

http feign socket mq

多线程并发

线程安全的特性

原子性 一个线程操作是不能被其他线程打断

有序性 线程在执行程序是有序的

可见性 一个线程修改数据后,对其他线程是可见的

volatile

使用volatile关键字可以保证线程的有序性和可见性,保持有序性是因为他可以让JVM不在指令重排,JVM执行时会把Class文件编译为一个个的命令去执行,CPU为了程序的执行性能会对指令进行重排.

他是基于内存屏障来可见性和有序性的,内存屏障本身就是一类同步屏障的命令,他提供了避免重排序的功能

内存屏障会把线程中工作内容改变后的数据直接刷回主内容 从而实现了数据的可见性。

单例模式

双重检查锁

单例模式他是首先使用volatile关键字定一个了一个静态的对象并且是私有的,然后提供了一个私有的静态无参构造方法,并开发了一个公共的方法来创建对象。从而使得创建该对象必须使用方法来进行创建。之后又进行判断只有当这个对象为空时才会创建对象并且反复引用也只会引用这个对象本身,之后又使用了Synchronized关键字以及复查判断的形式保证了线程安全的问题。

Spring集成线程池

在配置类上添加@EnableAsync注解代表开发多线程异步

在方法上添加@Async注解表示当前方法开启异步调用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值