Java多线程

1.并行与并发

并行是指同一时间执行多条指令

并发是指同一时间线程轮流使用CPU ,轮流执行指令

2.创建线程池的四种方式

1.继承Thread类

2.实现Runnable接口(无返回值)

3.实现Callable接口(有返回值)

4.通过线程池创建线程

3.Run() 和 Start() 的区别

1.run调用同一个线程

2.start每次都开启一个新的线程进行调用

4.线程包括哪些状态,状态之间是如何变化的

线程总共有六种状态,新建,可运行, 终结 ,阻塞,等待(wait) ,有时限 (sleep)

我简单介绍一下状态是如何切换的

在一个线程新建但是没有调用start方法的时候 是处于新建状态的, 如果调用了start方法,就会进入到可运行状态,执行完代码 进行到终结状态 。 这是一个线程正常情况下的执行流程 。

阻塞是当线程获取锁失败之后 进入到阻塞状态,只有当持有线程的锁释放锁的时候,他会按照一定的规则去获取锁,获取后变成可运行状态。

等待是线程获取锁后,调用了wait方法 此时进入等待状态,当其他线程调用notify或者notifyall方法后,会恢复成可运行状态

有时限是线程获取锁后,调用了sleep方法,此时进入有时限状态,不需要主动去唤醒他,等睡眠时间结束后就会自然恢复成可运行状态。

5.wait和sleep的区别

wait是Obejct的成员方法,每个对象都有

sleep是thread 的静态方法。

wait需要被唤醒, sleep自然醒来

wait方法执行后会释放对象锁,而sleep方法执行后不会释放对象锁

6.Synchronized锁的理解(非公平锁-悲观锁)

注: Monitor(监视器) 由jvm提供 c++实现

Synchronized 是采用一种互斥锁的方式,让同一时刻只有一个线程可以持有对象锁

Synchronized的底层采用的是monitor ,monitor 是jvm提供的 ,由c++实现, 线程获取锁需要使用对象锁关联monitor ,

在monitor的内部由三个属性, 分别是owner ,entrylist ,waitlist

owner是获得锁的线程 ,并且只能关联一个, entrylist里面关联的是处于阻塞状态的线程, waitlist里面关联的是处于等待状态的线程

monitor属于重量级锁,它涉及到了用户态和内核态的切换,进程的上下文切换,性能是比较低的。

所以在jdk1.6版本的时候 引入了两种新型的锁机制,分别是偏向锁和轻量级锁 ,

然后我来介绍一下Synchronized锁的升级过程

(偏向锁-可重入)在锁只被一个线程持有的时候,并且很长一段时间都只有这一个线程在使用锁,那么这个锁就是一个偏向锁,它只会在第一次获取锁的时候进行一个CAS 操作, 之后再获取锁,只需要判断mark word 里面是否为自己的线程id即可,而不是每次都进行CAS操作

(轻量级锁-可重入)线程加锁的时间是错开的,没有竞争的时候,可以使用到轻量级锁,轻量级锁修改了对象头的锁标志,每次都只进行了CAS操作 ,保证了原子性,相比重量级锁,它的性能提高很多

(重量级锁)底层采用monitor实现,涉及到了用户态和内核态的切换,进程的上下文切换,性能比较低。

标注: 对象的内存结构

7.JMM (Java Memory Model)Java内存模型

每一个线程有一个工作内存,工作内存中由一个共享变量的副本

在主内存中存在共享变量。

线程对变量的所有操作都必须在工作内存当中完成,不能直接操作主内存当中的数据。线程之间的值传递需要通过主内存完成。

8.CAS (Compare And Swap)比较再交换

是一种乐观锁的思想,在无锁状态下保证了线程操作数据的原子性 。比如当两个线程去操作共享变量副本,在第一个线程操作完之后,第二个线程想继续操作的时候,就会先去比较自己存的共享变量的值和主内存当中的值是否一致,一致的话再执行自己的操作,不一致的话就会将数据更新成主内存当中的数据,再进行对数据的运算。

9.AQS(AbstractQueuedSynchronizer)是一个抽象类

它是构建锁或者其他同步组件的基础框架

常见的实现类:

1.ReentrantLock 阻塞式锁 (默认非公平锁)

2.Semaphore 信号量

3.CountDownLatch 倒计时锁

工作机制:

1.在AQS中使用到了一个volatile 修饰的 state 属性来表示资源的状态,0代表无锁, 1代表有锁

2.提供了一个基于FIFO(First Input First Output)的等待队列 ,类似于Monitor的entrylist

3.条件变量来实现等待,唤醒机制,支持多个条件变量,类似于Monitor的WaitSet

多个线程如何保证原子性

在去修改state状态的时候,使用到了cas自旋锁来保证原子性。 修改失败的线程会进入FIFO队列中等待。

AQS是公平锁还是非公平锁

当新的线程与FIFO队列中的线程共同争抢资源的时候,是非公平锁

当新的线程到队列中等待,只让FIFO的head线程获取锁,是公平锁

它有一个实现类是ReentrantLock 默认是非公平锁

10.ReentrantLock 可重入锁

相对于Synchronized它具备一下特点

1.可中断

2.可以设置超时时间

3.可以设置公平锁

4.支持多个条件变量

实现原理:

它主要利用CAS+AQS队列来实现的。支持公平锁和非公平锁。

在构造方法中有一个可以选择的参数 默认是非公平锁 , 当设置成true 的时候 就表示成公平锁 。 公平锁的效率相比于非公平锁是比较低的。所以在多线程的访问下,公平锁的吞吐量会比较的低。

使用步骤:

因为它是一种手动锁,需要手动获取锁和释放锁,它更加灵活,但是也要注意释放锁,避免一个死锁的情况发生,所以通常需要配合try/finally语句来实现。 在finally中释放锁,保证即使出现了异常也能正常释放锁。

11.Volatile 关键字

volatile 是一个关键字,可以修饰类的成员变量、类的静态成员变量,主要 有两个功能

第一:保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的,volatile关键字会强制将修改的值立即写入主存。

第二: 禁止进行指令重排序,可以保证代码执行有序性。底层实现原理是,添加了一个内存屏障,通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化

12.线程池的创建方式

JDK默认提供了四种方式创建,具体的名字我记不太清楚了,因为这四种方式都有一定的缺点,并且在我们公司的项目中也是禁止使用的,项目中我们通常使用自定义的线程池来进行创建。

13.线程池的核心参数

核心参数总共有七个,分别是

核心线程数

最大线程数

非核心线程数存活时间

存活时间单位

最大等待队列数量

线程工厂

拒绝策略(四种)

1.抛异常(默认)

2.由调用者执行任务

3.丢弃当前任务

4.丢弃最早排队的任务

14.如何确定核心线程数

是这样的,我们公司当时的规范是,为了减少线程上下文的切换,要根据当前部署的cpu的核心数量来确认

通常是cpu核心数量+1

15.线程池的执行原理

当线程数量大于等待队列的数量的时候 会创建非核心线程 来执行任务, 如果都满了 那么会执行拒绝策略

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MingZhe1008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值