多线程知识点整理

多线程:

           多线程其实就是指线程在同一时间在cpu上同时进行。具体分为两种模式:一种是指多条线程在同一个cpu上分段时间运行,其实就是并行的意思。一种是多条线程在cpu上同时运行的,其实就是并发的意思。

多线程的问题

              多线程主要的问是,在多条线程运行情况下,会出现以下情况:

               1.多个线程同时竞争同一个资源的问题,导致线程出现安全问题

                2.线程之间的调用资源互相等待,如下图:

                      那么问题来了,为了避免线程安全问题,我们应该如何避免线程安全的问题了:

                      1.进行加锁操作:就是对多个线程要都是使用的资源进行加锁操作,加锁的操作有三个个思想方向:

                       悲观锁:所谓的悲观锁,其实就是一种悲观的心态,也就像是你是对什么事情都报悲观的看法,认为所有的事 , 不好的影响是一定会发生的,基于这个观点。所有在对多线程中要使用的公共资源,你也认为发生线程不安全的问题是一定要发生的,那就先把她加一把锁上,这样让每一来调用资源的线程,都先看看资源是否在使用、如果已经被其中一个线程使用,其他线程就等待。

                       乐观锁:与悲观的看法不一样的是,你认为发生不好事情的几率是很小的,所以基于这个观点,在多线程使用公共资源的时候,你认为大多时候,线程使用都市安全的,那么我们在多条线程来调用资源的时候,就不需要来想悲观锁一样来加把锁上,而是直接就调用。只是看看调用的时候,资源的状态如何就行。其中一种很经典的思路cas(比较替换)就是乐观锁的实现。

                      cas 中的逻辑就是,在线程进入调用资源的时候,需要获取到资源的值,这个值最好是具有唯一性的,如时间戳,版本号等,然后在要对资源的数据进行修改的时候,在吧前面获取的原本的资源值与当前资源的值进行比较。如果相等,就说明资源在当前线程运行时。没有进行过改变的操作(要防止ABA问题)。就对资源进行值的变更。如果不相等,就说明已经进行了相关的变更操作。次线程需要重新获取资源的新值,在来比较。现在的java的atomic包中的类,都是实现了cas的乐观锁的。

                     ABA问题

                    ABA的问题就是cas思想中一个经典的问题。其出现的的情况大至如何。说先有两条线程A,B 来获取到资料的值为A。 然后线程A先对资源进行了操作,把资料的值改为了B。就在线程A执行完,线程B执行前。来了条线程C,其获取到资源的值为B,然后通过对比比较之后,把资源的值B改为了A。那么当前的资源的值就是A,在线程C执行完之后,线程B在来执行对比比较。发现资源的值是A,与线程B最先获取的值是相等的,然后线程B就执行了对资源值的修改。其实在线程B执行之前,资源的值是发生了变化的A变成了B,再从B变成了A。所以线程B不应该执行,而是应该进入循环,在来一次获取值,对比值。这也是前面我问什么提醒在cas的时候,要把标识值用友唯一性的东西来做的原因

                       前面说的加锁的悲观锁和乐观锁,但是悲观锁的效率低,不利于高并发的情况。乐观锁的效率高,但是对内存的消耗也大,也是一个不足。那么有没有既考虑到效率,有考虑到内存的问题了。其实还真有一种锁。读写锁。

                  读写锁:

                首先要说明,不是所有的读写锁都满足既考虑到效率,有考虑到内存的话,我说的是读写锁中采用共享模式,独占模式相结合的,如:    ReentrantReadWriteLock类,其就是能够多线程读取资料,写线程的时候是加了锁的。但是这要先介绍一种思路,AQS,就是同步器的概念。在AQS的,是会有个虚拟先进先出的队列来装插入队列中的线程。而且里面还是双向链表结构。然后其有有个状态来表示公共资源。而线程对公共资源的使用方式分为两种。一种是独享占用,一种共享,其中独享占用有分为公平竞争和非公平竞争。公平竞争就是先到先得的意思,指先进入队列的线程优先获取资源;而非公平竞争是指队列中的线程自由竞争资源,谁先获取到资源,谁就使用。

           2.其实保证线程安全,也可以不用加锁的模式。就比如spirng中ioc中生成的对象默认的是单例模式,但是我们可以设置为prototype多利模式;而且针对我们还可以用TherdLocal这个类,来对线程中公共使用的对象复制,然后使用,只有记得指使用玩之后,将复制的对象删除,避免内存溢出的问题就行。

           3.还有比如利用redis中的setnx 来保证线程的安全,也是可以的。