Java并发编程基础知识梳理

279 阅读3分钟

1.为什么要用到并发

  • 充分发挥多核cpu的计算能力提高程序执行效率;

  • 不影响程序正常运行下的情况下,方便拆分不用的业务提高程序性能

2.并发编程的优缺点

2.1 频繁的上下文切换

时间片是cpu分配给线程的执行时间,每个线程在(争抢)获得了cpu的时间片才能执行,由于每个线程都可能抢到时间片,所以各个线程都在切换执行,由于时间非常短,所以各个线程切换速度非常快,会让我们觉得每个线程在同时进行。然而每次线程切换时,都需要保存当前的状态,以便能恢复之前的状态,所以在切换时会非常损耗性能,所以一旦过于频繁的切换反而会无法体现多线程编程的优势。为了减少并发编程的上下文切换可以使用以下几种常见的方法。

  • 无锁并发编程:比如concurrentHashMap的锁分段思想,不同的线程处理不同段的数据数据,以此来减少在多线程竞争下的上下文的切换的时间。

  • cas算法:比如atomic下的cas算法,使用了乐观锁,可以有效的减少一些不必要的锁竞争带来的上下文切换。

  • 尽量避免创建不必要的线程:创建满适合当前任务处理的线程数量就好了,不要过多的创建不必要的线程,而且创建线程数量的大小要和当前服务器的硬件配置要相符。

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

2.2 线程安全问题

线程安全问题是由于多线程编程中,不同线程对同一个共享数据进行写的操作导致出现数据脏读,数据污染的问题。

死锁:在多线程编程中为了线程安全程序员一般会进行对线程的保护,一般会对可能会出现线程安全问题的代码段加锁,该代码段也叫临界区,保证该区域代码同时只能有一个线程执行,需要注意的是我们在加锁时如果不注意可能会出现死锁。死锁问题具体请看后面的文章。

3.同步和异步的区别

比如我们执行一个方法,同步是要当我们执行到这个方法时,一定要在这个方法执行完后代码才能继续执行,异步是当我们执行到这个方法时不管这个方法是否执行完都会执行后面的代码,也就是这个方法在另一线程中被执行。

4.并发和并行

并发是指多个线程通过抢占cpu时间片来交替执行,并行是真正意义上的多个线程同时执行。如果系统只有一个单核cpu,那么该系统的线程无法并行,只能并发(通过抢占cpu时间片来交替执行)。在多核cpu的情况下,系统才能达到并行。

5.阻塞和非阻塞

阻塞一般出现在多线程之间的相互影响,比如一个线程占有了临界区资源(获取了锁),其他线程必须挂起等待该线程释放锁资源,这些线程在此时会变成阻塞状态。非阻塞就是没有线程会阻塞其他线程,所有线程都会抢占cpu时间片尝试执行下去。让线程出现阻塞状态有很多种方式具体内容会在后面的文章中介绍。