1. 什么是线程安全和线程不安全?

简单的理解就可以认为,加锁的线程是安全的,不加锁的线程是不安全的。
线程安全:在执行多线程的时候,加上锁机制,同一时间只允许一个线程进行操作,其他线程都在后面等待。直到它执行完成,后面的才能进来。避免了数据不一致和读到脏数据的问题。
线程不安全:在执行多线程的时候,没有使用锁机制,多个线程会并列进行操作,有可能会造成A线程读到B线程的旧数据问题,也会造成两次写操作数据不一致的问题。

线程安全问题都是由全局变量和静态变量引起的,如果所有线程都是读操作,没有写,也可以认为是线程安全的。如果由多个线程执行写操作,这个时候就需要考虑进行线程同步。

2. 什么是自旋锁?

自旋锁是基于SMP架构的一种low-level机制。
当线程A想要获取一把锁而这把锁又被其他线程持有的情况下,线程A会在一个循环里自旋,并反复尝试获取锁。
自旋锁是及其消耗性能的,在使用的时候,持有锁的线程应该即使释放锁,在sleep之前也应该释放锁,不然其他线程就会一直自旋并尝试获取锁,会极大浪费CPU时间。

3. 什么是CAS?

是compare and swap的缩写,中文翻译比较和交换。
CAS并不通过JVM,而是利用JNI,直接调用CPU的汇编指令。
通过CPU的CAS指令,和JNI来完成java的非阻塞式算法,实现原子操作,其他原子操作也是利用类似特性完成的。
整个JUC(java.util.concurrent)都是建立在CAS基础之上,相比起以前的sync,CAS提高了很多性能。
CAS执行:
CAS执行原子性操作会用到三个概念。内存值V,预估值A,更新值B。
当前执行一条写操作时,它会先拿V和A比较,如果相等,再把更新值B赋值给V。如果不想等,则认为是已经被修改过了,则不让进行操作。
CAS是乐观锁技术:
当多个线程进行更新同一个变量,只能又一个成功,其他的都失败,失败的线程不会被挂起,而是被告知本次竞争失败,并可以继续尝试。
CAS的优点
所有的读,写操作多是原子性的
CAS的缺点
①CAS会后续带来经典的ABA问题
②并且在线程冲突严重的时候,还会大幅降低性能。
③只能针对单个变量进行操作,不能用于多个变量进行原子操作。

4.ABA问题是什么意思?要怎么去解决?

java中经典的ABA问题,具体是指:
假设内存值V的具体值是A,这时候一个线程把它修改成了B,再又修改回了A。这个时候,程序就无法辨别内存值到底是有没有被修改过。最典型的就是如果别人挪用了你卡中的钱,在你发现之前又换了回来,这并不能说就没有改变过。所以我们在使用CAS的时候,除了最终的结果以外,也要考虑其过程的变化。
具体的实现我们可以使用JUC提供的AtomicStampedReference类。这个类中维护了一个时间戳,就像是一个版本号。这个类就像一个监视者,当我们要去修改被它监视的变量,同时也必须同步更新时间戳,这样即使后来的结果一样,但是通过时间戳我们也能看出这个变量到底有没有被修改过。

5. 什么是Executors框架?

在java中,我们想要实现线程池技术,就需要使用到Executiors。
通常情况下,我们会使用它的实现类,ThreadPoolExecutors。
ThreadPoolExecutor中有四种创建线程池的方式:
CachedTheadPool: 缓存线程池。这种线程池没有核心线程,最大线程数等于Integer的最大值。这种线程池比较灵活,当需要的时候它回去看有没有空闲线程如果有就用,如果没有则创建一个。如果一个线程超过60s还没使用,则会被回收。
这种线程池适合用于耗时小,任务量大的情况。

FixedTheadPool: 定长线程池。只有核心线程,没有非核心线程,核心线程的数量就是线程池的最大数量。可以用来控制并发数,当要使用时即使有空闲线程也不会使用,而是去创建一个新线程,直到达到最大线程数才回去复用空闲线程。当超过最大核心线程时,其余线程之后排队等待。
这种线程池可以用来控制并发,适合用于执行长期的任务。

ScheduledThreadPool: 周期性线程池。可以定时执行一些周期性的任务。有核心线程,也有非核心线程,非核心线程的最大数也是等于Integer的最大值。它是四种线程池中唯一的一个可以用来延迟执行和周期性执行任务的线程池。
适合用于周期性执行任务的场景。如定期同步数据

SingleThreadPool: 单个线程池。只有一条单个线程,保证线程按照我们指定的队列模式执行(FIFO,LIFO,优先级等)
适用于需要有序执行的任务场景。

线程池相关概念:
核心线程:
线程池执行流程中,被会优先使用。即使核心线程空闲,也不会被回收。
非核心线程:
在执行流程中,只有当核心线程满了,并且工作队列也满了之后才回去选择使用非核心线程。非核心线程有最大存活时间,超过时间还没有被使用,则会被回收。

6. 什么是原子操作?在Java Concurrency API中有哪些原子类(atomic classes)?

原子操作是指避免其他操作对其产生影响,是一种为了避免数据不一致行问题的必要手段。
如i++就不是一个原子操作,多线程情况下,其他线程有可能读到操作的值。为了避免这种情况,我们就需要考虑其原子性,使其自增的操作要么全部成功,要么全部失败。
JUC里给我们提供了对数字进行原子操作的类,如AtomicInteger,AtomicDouble,AtomicLong等,让我们可以进行数字的原子性操作并且不需要使用同步代码。(Atomic**是基于CAS实现的原子操作)

7. 什么是阻塞队列?如何使用阻塞队列来实现生产者-消费者模型?