并发编程基础 二


1.什么是并行和并发

并发和并行都是多任务处理的概念,但含义不同

并行是指两个任务或者多个任务同一时刻执行,即同一时刻有多个任务同时执行;多核cpu可以实现并行处理;在并行处理中,所有任务之间都是相互独立的,不需要等待其他任务的完成。

并发是指两个或多个任务在同一时间段内同时执行,即在同一时间段内多个任务交替执行;单核 CPU 可以通过轮流执行各个任务来实现并发处理。在并发处理中,任务之间可能会相互影响,需要考虑任务的顺序和优先级,也需要考虑任务之间的同步和通信问题。

如果是多个任务同时执行,就是并行;如果是多个任务交替执行,就是并发。并行处理通常需要多核 CPU 来支持,可以提高处理速度;而并发处理可以在单核 CPU 上实现,但需要考虑任务之间的同步和通信问题。

2.什么是活锁

假设有两个线程,线程 1 和线程 2,它们都需要资源 A/B,假设线程 1 占有了 A 资源,线程 2 占有了 B 资源;

由于两个线程都需要同时拥有这两个资源才可以工作,为了避免死锁,1 号线程释放了 A 资源占有锁,2 号线程释放了 B 资源占有锁;此时 AB 空闲,两个线程又同时抢锁,再次出现上述情况,此时发生了活锁。

简单类比,电梯遇到人,一个进的一个出的,对面占路,两个人同时往一个方向让路,来回重复,还是堵着路。如果线上应用遇到了活锁问题,恭喜你中奖了,这类问题比较难排查。

3.单线程创建
  • 继承 Thread 类
  • 实现 Runnable 接口;

注意的问题:

不管是继承 Thread 类还是实现 Runable 接口,业务逻辑写在 run 方法里面,线程启动的时候是执行 start()方法

开启新线程不影响主线程的代码执行顺序,也不会阻塞主线程的执行;新线程和主线程的代码执行的执行顺序是不保证先后的

多线程的目的是让cpu忙起来

通过查看 Thread 的源码可以看到,Thread 类是实现了 Runnable 接口的,所以这两种本质上来讲是一个

public class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }
4.终止线程运行的情况

线程调度器选择优先级最高的线程运行

以下情况会终止线程:

  • 线程体中调用了 yield()方法,让出了对 CPU 的占用权;
  • 线程体中调用了 sleep()方法,使线程进入睡眠状态;
  • 线程由于 I/O 操作而受阻塞;
  • 另一个更高优先级的线程出现;
  • 在支持时间片的系统中,该线程的时间片用完。

5.如何减少上下文切换

减少上下文切换的方法:无锁并发编程,CAS算法,使用最少线程和使用协程

无锁并发编程:多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的 ID 按照 Hash 算法取模分段,不同的线程处理不同段的数据。


CAS 算法:Java 的 Atomic 包使用 CAS 算法来更新数据,而不需要加锁。


使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多多线程来处理,这样会造成大量线程都处于等待状态。


协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换

6.什么是死锁

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

线程 1 己经持有了资源 2,它同时还想申请资源 1,线程 2 已经持有了资源 1,它同时还想申请资源 2,所以线程 1 和线程 2 就因为相互等待对方已经持有的资源,而进入了死锁状态。

7.写出死锁代码

四个条件:

互斥条件:一个资源同时只能有一个线程占有.其他线程只能等待.


请求并持有条件:当前线程已经获取到一个资源,又获取其他资源,其他资源被别的线程占有,当前线程等待,但是不释放持有资源.


不可剥夺条件:占有资源期间,不能被其他线程剥夺,只能自己释放.


环路等待条件:等待资源形成环形链.a 被 A 占有,b 被 B 占有,A 想获取 b,B 想获取 a

8.如何避免死锁呢?

1.要想避免死锁,只需要破坏掉至少一个构造死锁的必要条件即可,目前只有请求并持有条件和环路等待条件是可以被破坏的。考虑死锁产生的条件:互斥访问、占有并保持、循环等待。针对以上几点,可以:资源一次性分配、占有时可被打断、考虑资源分配顺序。

2.避免一个线程同时获取多个锁。


3.避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。


4.尝试使用定时锁,使用 locktryLock(timeou t)来替代使用内部锁机制。


5.对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

9.线程,进程,协程的区别?

进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位.

线程则是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。操作系统在分配资源时是把资源分配给进程的,但是 CPU 资源比较特殊,它是被分配到线程的,因为真正要占用 CPU 运行的是线程,所以也说线程是 CPU 分配的基本单位。在 Java 中,当我们启动 main 函数时其实就启动了一个 JVM 进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程

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

进程:静态分配内存资源的最小单位

线程:动态执行任务的最小单位

协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。协程也叫纤程.

线程是在内核态调用的,协程在用户态调用,避免了上下文切换


10.缓存一致性协议

MESI 是保持一致性的协议。

它的方法是在 CPU 缓存中保存一个标记位,这个标记位有四种状态:

M: Modify,修改缓存,当前 CPU 的缓存已经被修改了,即与内存中数据已经不一致了
E: Exclusive,独占缓存,当前 CPU 的缓存和内存中数据保持一致,而且其他处理器并没有可使用的缓存数据
S: Share,共享缓存,和内存保持一致的一份拷贝,多组缓存可以同时拥有针对同一内存地址的共享缓存段
I: Invalid,实效缓存,这个说明 CPU 中的缓存已经不能使用了
CPU 的读取遵循下面几点:

如果缓存状态是 I,那么就从内存中读取,否则就从缓存中直接读取。
如果缓存处于 M 或 E 的 CPU 读取到其他 CPU 有读操作,就把自己的缓存写入到内存中,并将自己的状态设置为 S。
只有缓存状态是 M 或 E 的时候,CPU 才可以修改缓存中的数据,修改后,缓存状态变为 M
 

11.finally不执行的情况

在 Java 的finally块中通常执行的是一些必须要在退出try块时执行的代码,不受异常是否抛出的影响。

然而,有几种情况下finally块不会执行:

1.System.exit() 或 JVM 崩溃:
当程序调用System.exit()方法时,Java 虚拟机会立即退出,不再执行任何未完成的代码,包括finally块。
如果在finally块中执行了一个会使 JVM 崩溃的操作(如死循环或异常死锁等),则finally块不会完成执行。


2.线程无法停止:
如果在finally块中有一个无法停止的线程(如Thread.stop()方法),finally块可能无法完成执行。


3.处理器或虚拟机崩溃:
在某些极端情况下,如处理器错误或 Java 虚拟机崩溃,finally块可能不会执行。


4.在 try 块中出现死循环:
如果在try块中出现一个无限循环,finally块将不会执行,因为代码永远不会跳出try块。


5.System.exit() 或 Runtime.halt() 在 finally 块中被调用:
如果在finally块中调用了System.exit()或Runtime.halt()来退出 JVM,那么 JVM 将立即终止,finally块的执行也将被中断。


6.**守护线程中的 finally:**当只剩下守护线程在运行时,JVM 认为它已经完成了所有需要执行的任务,于是会立即退出,不会等待守护线程的finally块执行完毕。这意味着,如果守护线程中有finally块,当 JVM 退出时,这些finally块可能不会被执行。


总之,finally块在大多数情况下都会执行,但在某些极端情况下,如程序终止或 JVM 崩溃等情况下,finally块可能不会被执行。因此,在使用finally块时,应该确保其中的代码是可靠的,不依赖于异常处理或 JVM 的状态
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值