并发(一、基础)

1、并行 跟 并发 的区别

从操作系统的角度来看,线程是CPU分配的最小单位。

  • 并行 就是同一时刻,两个线程都在执行。这就要求有两个CPU去分别执行两个线程。
  • 并发 就是同一时刻,只有一个执行,但是一个时间段内,两个线程都执行了。并发的实现依赖于CPU切换线程,因为切换的时间特别短,所以基本对于用户是无 感知的。

就好像我们去食堂打饭,并行 就是我们在多个窗口排队,几个阿姨同时打菜;并发 就是我们挤在一个窗口,阿姨给这个打一勺,又手忙脚乱地给那个打一勺。


2、进程 和 线程 的区别

  • 进程:进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。
  • 线程:线程是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。

操作系统在分配资源时是把资源分配给进程的,但是 CPU 资源比较特殊,它是被分配到线程的,因为真正要占用CPU运行的是线程,所以也说线程是CPU分配的基本单位。

比如在Java中,当我们启动 main 函数其实就启动了一个JVM进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。

一个进程中有多个线程,多个线程共用进程的堆和方法区资源,但是每个线程有自己的程序计数器和栈。


3、线程 的创建方式

Java中创建线程主要有三种方式:继承Thread类实现Runnable接口实现 Callable接口

详细内容可参考 创建线程的三种方式

● 为什么调用 start() 方法时会执行 run() 方法,那怎么不直接调用 run() 方法?

JVM执行 start() 方法,会先创建一条线程,由创建出来的新线程去执行thread的 run() 方法,这才起到多线程的效果。如果直接调用Thread的 run() 方 法,那么 run() 方法还是运行在主线程中,相当于顺序执行,就起不到多线程的效果。

● Thread 和 Runnable 的区别

Thread类适合直接创建新线程,而Runnable接口适合定义线程要执行的任务,并可以 与其他接口组合使用。

特点ThreadRunnable
继承关系接口
代码复用不方便,每个线程需要创建新实例方便,多个线程可以共享同一实例
灵活性相对较低,只能继承Thread类相对较高,可以与其他接口组合
可控性相对较低,需要手动管理线程相对较高,可以通过线程池管理

4、线程常用调度方法

详细内容可参考 线程常用方法

在这里插入图片描述


5、线程六大状态

详细内容可参考 线程六大状态

状态说明
NEW初始状态:线程被创建,但还没有调用start()方法
RUNNABLE运行状态:Java线程将操作系统中的就绪和运行两种状态笼 统的称作“运行”
BLOCKED阻塞状态:表示线程阻塞于锁
WAITING等待状态:表示线程进入等待状态,进入该状态表示当前线 程需要等待其他线程做出一些特定动作(通知或中断)
TIME_WAITING超时等待状态:该状态不同于 WAITIND,它是可以在指定 的时间自行返回的
TERMINATED终止状态:表示当前线程已经执行完毕

在这里插入图片描述

● BLOCKED 和 WAITING 的区别

  • BLOCKED 状态表示线程被阻塞,无法继续执行,通常是因为等待获取锁。
  • WAITING 状态表示线程正在等待其他线程的通知,通常是因为调用了wait()方法、 join()方法或LockSupport.park()方法。

这两种状态的区别在于阻塞状态是等待获取锁,而等待状态是等待其他线程的通知。

● WAITING 和 TERMINATED 的区别

  • WAITING 状态表示线程在等待其他线程的通知或中断
  • TERMINATED 状态表示线程已经执行完毕,不再执行任何代码。

WAITING 状态是暂时的,可以再次进入 RUNNABLE 状态,而 TERMINATED 状态是永久的,线程不会再进入任何状态。


6、线程上下文切换

使用多线程的目的是为了充分利用CPU,但是我们知道,并发其实是一个CPU来应付多个线程。

在这里插入图片描述

为了让用户感觉多个线程是在同时执行的,CPU 资源的分配采用了时间片轮转,也就是给每个线程分配一个时间片,线程在时间片内占用 CPU 执行任务。当线程使用完时间片后,就会处于就绪状态并让出 CPU 让其他线程占用,这就是上下文切换。


7、守护线程

详细内容可参考 守护线程 deamon

Java中的线程分为两类,分别为 **daemon 线程(守护线程)**和 user 线程(用户线 程)

在JVM 启动时会调用 main 函数,main函数所在的钱程就是一个用户线程。其实在 JVM 内部同时还启动了很多守护线程, 比如垃圾回收线程。

● 那么守护线程和用户线程有什么区别?

区别之一是当最后一个非守护线程束时, JVM会正常退出,而不管当前是否存在守护线程,也就是说守护线程是否结束并不 影响 JVM退出。换而言之,只要有一个用户线程还没结束,正常情况下JVM就不会退出。


8、线程间的通信方式

在这里插入图片描述

● volatile 和 synchronized 关键字

关键字 volatile 可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。

关键字 synchronized 可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。

● 等待 / 通知机制

可以通过Java内置的 等待/通知机制(wait()/notify())实现一个线程修改一个对象的值,而另一个线程感知到了变化,然后进行相应的操作。

● 管道输入 / 输出流

管道输入/输出流和普通的文件输入/输出流或者网络输入/输出流不同之处在于,它主要用于线程之间的数据传输,而传输的媒介为内存。

管道输入/输出流主要包括了如下4种具体实现:PipedOutputStreamPipedInputStreamPipedReaderPipedWriter,前两种面向字节,而后两种面向字符。

● 使用 Thread.join()

如果一个线程A执行了 thread.join() 语句,其含义是:当前线程A等待thread线程终止之后才从 thread.join() 返回。。线程Thread除了提供 join() 方法之外,还提供了 join(long millis)join(long millis,int nanos) 两个具备超时特性的方法。

● 使用 ThreadLocal

ThreadLocal,即线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构。

这个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。 可以通过 set(T) 方法来设置一个值,在当前线程下再通过 get() 方法获取到原先设置的值。

详细内容可参考 并发(二、ThreadLocal)


9、死锁(补充)

死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现 象,在无外力作用的情况下,这些线程会一直相互等待而无法继续运行下去。

在这里插入图片描述
● 死锁的产生必须具备以下四个条件:

  1. 互斥条件:线程对己经获取到的资源进行它性使用,即该资源同时只由一个线程占用。如果此时还有其它线程请求获取获取该资源,则请求者只能等待,直至占有资源的线程释放该资源。
  2. 请求并持有条件:一个线程己经持有了至少一个资源,但又提出了新的资源请求,而新资源己被其它线程占有,所以当前线程会被阻塞,但阻塞的同时并不 释放自己已经获取的资源。
  3. 不可剥夺条件:线程获取到的资源在自己使用完之前不能被其它线程抢占,只有在自己使用完毕后才由自己释放该资源。
  4. 环路等待条件:发生死锁时,必然存在一个线程所需资源的环形链,T1等T2,T2等T3,T3等…Tn等T1。

● 如何避免死锁?

至少破坏死锁发生的一个条件!

其中,互斥条件我们没有办法破坏,因为用锁为的就是互斥。不过其他三个条件都是有办法破坏掉的。

  • 请求并持有:可以一次性请求所有的资源。
  • 不可剥夺:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源,这样不可抢占这个条件就破坏掉了。
  • 环路等待:可以靠按序申请资源来预防。所谓按序申请,是指资源是有线性顺序的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后就不存在环路了。

● 死锁排查

可以使用 JDK 自带的命令行工具排查:

  1. 使用 jps 查找运行的 Java 进程:jps -l
  2. 使用 jstack 查看线程堆栈信息:jstack -l 进程id

还可以利用图形化工具,比如 JConsole。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

纯纯的小白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值