一、为什么需要多线程
cpu、内存、io设备的速度有差异,多线程是为了合理利用cpu的高性能,平衡三者的速度差异
但是多线程会产生可见性、原子性和有序性问题,导致线程不安全。可见性由cpu缓存引起,原子性由分时复用引起,有序性由重排序引起

二、Java多线程实现方法
1.实现runnable接口
2.实现callable接口
3.继承Thread类
runnable和callable接口只能代表一个可以在线程中执行的任务,而不是线程,所以想要执行还是需要新建线程,用start方法启用

三、锁
锁是为了保证多线程的线程安全,一个线程获取到锁以后,其他线程就无法获取到锁,可以保证同一时间只有一个线程在操作数据。线程获取不到锁的时候会进入阻塞状态,阻塞状态会释放cpu资源,如果获取到锁,将进入就绪状态等待cpu时间片。阻塞本身是会释放cpu资源达到不占用cpu的目的,但是代码中的 阻塞->运行 同样会造成cpu时间片切换,消耗资源
1.乐观锁和悲观锁
是广义上的概念,具体的实现方式不同
悲观锁认为自己在使用数据时一定有其他线程来修改数据,所以获取数据的时候先加锁,确保不被别的线程修改,syncchronized和Lock的实现类都是悲观锁。
乐观锁认为自己使用数据的时候没有别的线程来修改数据,所以不加锁,只在更新数据的时候判断之前有没有线程修改过数据,如果数据没更新过,当前线程会将数据写入;如果被更新过,则有不同的处理方法,抛异常、重试或者其他处理。乐观锁在代码中编程是不加锁的。
2.自旋锁
为什么要有自旋锁?阻塞和唤醒java线程需要操作系统切换cpu状态来完成,是需要消耗cpu时间的,如果锁住的代码中内容非常简单,比切换cpu的时间还少,那么一个线程获取不到锁马上进入阻塞状态释放cpu可能是不值得的。在多线程的环境下,如果一个线程请求锁,可以不让它放弃cpu时间片而是自旋等待前面线程的锁,可以等到的话,就避免了切换线程的开销。
自旋锁在锁很快释放的时候效果是好的,如果锁被持有很久,那么它会占用大量处理器时间,所以可以设置自旋次数,Java默认10次。
自适应自旋锁是更聪明的锁,自旋的时间不是固定的,而是JVM预测的,如果自旋的时候很少成功获取到一个锁,那么以后获取这个锁的时候可能就不自旋了以免浪费cpu时间片。
3.公平锁和非公平锁
公平锁是多线程按获取锁的顺序在队列中排队,队列中获取锁的顺序是从头到尾,优点是等待锁的线程不会出现一直获取不到,缺点是系统整体的吞吐量比非公平锁低。
非公平锁是在获取锁的时候直接尝试获取一下,如果能获取到,此线程无需阻塞就直接获取到锁了,如果获取不到就放在队列中排队,优点是可以减少唤醒线程的开销,缺点是队列中的线程可能一直在等待。
4.可重入锁
也可称为递归锁,锁对象是同一个的前提下,外层方法在获取到锁时,内层方法可以自动获取到锁,否则内层方法获取外层方法的锁时可能会死锁。Java中ReentrantLock和synchronized都是可重入锁。

四、线程
Runnable接口,定义run方法
Callable接口,定义call方法
Future接口,定义了获取任务执行结果、取消任务等方法
RunnableFuture接口,继承Runnable和Future,拥有他们的方法

FutureTask实现了RunnableFuture接口,它可以当成Runnable任务执行,也能作为Future获取到结果。当线程的执行需要返回结果时,用到Callable接口和Thread类,Thread只能接收Runnable,所以用实现了Runnable的FutureTask,才能放入Thread启动。在没有用到线程池的时候这样就可以获取到结果了,用到线程池时ThreadPoolExecutor也是内部创建了FutureTask达到效果的。
维护一个Callable对象,构造方法传入一个Callable对象或者传入Runnable封装成Callable对象
定义了state表示任务执行的状态,在线程执行过程中会不断的设置该值,任务是否取消、任务是否完成都是直接比较一下state值
定义了Object的outcome表示结果,线程有结果后会赋值给它
线程的run方法是实际的执行,run方法中调用Callable的call接口执行业务代码,执行完毕后将结果给到outcome
获取结果的时候awaitDone等待执行结果,判断线程状态如果是执行完,就将结果返回
维护WaitNode类型的waiters,是一个链表,用get方法获取结果的那些线程都会放入链表中,等到有结果后会处理这个链表

五、Thread
实现了Runnable接口,但是它不是一个任务,而是真正的线程
Thread有名称、优先级、是否守护线程、Runnable对象target、ThreadGroup、threadLocals、inheritableThreadLocals、线程id等属性
可以看到线程中有ThreadLocalMap,所以线程独有该数据,可以从线程执行的任何过程中拿到
有另一个ThreadLocalMap inheritableThreadLocals,用于在创建线程时父线程传递信息到子线程。构造方法会指定是否继承父线程消息,默认是继承的,所以我们可以直接用

构造方法调用init方法,传入Runnable对象、线程名称等参数。
父线程就是创建该线程的线程,父线程的很多属性都会继承到该新线程上,比如是否守护线程、优先级和inheritThreadLocals
构造中设置了target为传入的Runnable对象;设置tid为线程id,使用的是原数字+1

Thread的大部分方法都是调用了native方法
run方法,会运行target的run方法,target是传进来的Runnable对象,该对象的run方法是我们自己写的业务
run方法需要被start方法调用,start是native方法,当Thread调用start的时候,JVM会调用run方法
start方法,首先判断一下线程状态是否为NEW初始化状态,如果不是就抛出异常,调用本地方法start0真正执行线程
sleep方法,让线程休眠一段时间,但是不会释放锁
json方法,是一个synchronized方法,主要用于等待某线程结束。主线程首先持有线程对象的锁,然后用wait方法释放线程对象的锁,进入等待状态等待唤醒,JVM在线程执行结束后notify将主线程唤醒

六、线程池
降低资源消耗(线程无限制地创建,然后使用完毕后销毁)
提高响应速度(无须创建线程)
提高线程的可管理性

Executor是线程池的基接口,定义了无返回值的execute方法,接收一个Runnable对象
ExecutorService实现了Executor,定义了线程池关闭方法、Callable对象的submit方法和Callable集合对象的invoke方法
AbstractExecutorService抽象类,实现了ExecutorService,重写了submit和invoke
ThreadPoolExecutor继承自AbstractExecutorService,是我们用的线程池

七、ThreadPoolExecutor
维护一个HashSet Worker,workers就是线程集合
维护一个BlockingQueue Runnable,workQueue是任务阻塞队列,任务被worker获取到然后执行

构造方法传入的参数:
this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
corePoolSize,核心线程数量,提交任务时创建核心线程,当线程数量超过该数量后放入队列中
maximumPoolSize,最大线程数量,任务在队列中满了后,继续提交任务会继续创建线程直到线程数量达到最大值,队列是无界队列时maximumPoolSize不生效
workQueue,工作队列,任务会放在该阻塞队列中,等待被线程执行。ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue是JDK提供的阻塞队列
keepAliveTime,线程空闲存活时间,线程没有任务执行的时候要终止,只在线程数大于corePoolSize时有用
threadFactory,线程工厂,不指定的话会使用默认的DefaultThreadFactory
handler,线程池的饱和策略,不指定的话默认是AbortPolicy
策略有下面几种
AbortPolicy: 直接抛出异常,默认策略;
CallerRunsPolicy: 用调用者所在的线程来执行任务;
DiscardOldestPolicy: 丢弃阻塞队列中靠最前的任务,并执行当前任务;
DiscardPolicy: 直接丢弃任务

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
ctl的低29位表示线程池中线程数,高3位表示线程池的运行状态
比如,RUNNING = -1 << COUNT_BITS,即高3位为111,该状态的线程池会接收新任务,并处理阻塞队列中的任务

内部类Worker继承自AbstractQueuedSynchronizer,实现了Runnable接口
Worker可以认为是消费者们,不断消费队列中的任务
构造方法设置了firstTask和thread
run方法重写Runnable的,这里就是线程的具体操作,包括执行firstTask和从workQueue队列里获取任务并执行

execute方法是执行任务的方法,传入一个Runnable对象,方法无返回值
1.先从ctl获取到当前线程数量
2.比较是否小于corePoolSize,如果小于的话,需要addWorker创建新的线程,实际创建的是Worker对象
3.Worker的构造方法传入firstTask作为执行的第一个任务,构造中创建thread的时候传入了Runnable对象Worker,所以Worker类中的run方法在thread.start的时候被调用
4.线程添加到workers集合中,设置一下largestPoolSize表示线程最大达到该数量,线程调用start方法开始启动Worker的run方法
5.Worker的run方法进行runWorker,如果fistTask不等于null的话表示刚传进来的任务,马上执行它,如果等于null的话getTask获取队列中的任务来执行,调用Runnable的run方法即可。任务执行的时候会进行加锁,用的是AbstractQueuedSynchronizer。
6.如果线程数量已经大于corePoolSize,用队列的offer方法添加到队列中,Worker会从队列中获取任务去执行
7.如果往队列中添加任务失败,就添加非核心线程,非核心线程最大maximumPoolSize,如果超出的话将会执行拒绝策略

submit方法是提交任务的方法,传入Runnable对象或者Callable对象,返回Future对象
1.将Runnable对象或者Callable对象封装成FutureTask,因为FutureTask也实现了Runnable,所以可以用execute方法执行
2.execute执行过程就是上面段落中内容,只是执行的目标从Runnable对象变成了FutureTask对象,FutureTask的run方法执行了Callable的call方法并填充了响应
3.外部可以用FutureTask对象获取到返回值

八、ThreadLocal
ThreadLocal是和线程绑定的,在Thread中有属性ThreadLocalMap
ThreadLocalMap是一个静态内部类,维护一个Entry数组table,key为当前ThreadLocal对象,value为自定义的对象,对ThreadLocalMap的操作都是间接对table这个数组操作,比如tab[i] = new Entry(key, value),table也会扩容,每次是原来2倍
ThreadLocal进行set的时候先获取到当前线程Thread,进而获取到ThreadLocalMap,将当前ThreadLocal对象作为key,设置的值作为value,放置于此map中;get的时候同样,获取到当前Thread和ThreadLocalMap,从map中获取值

InheritableThreadLocal继承自ThreadLocal,重写了childValue、getMap、createMap三个方法。
用于给子线程传递ThreadLocal数据,Thread里有threadLocals和inheritableThreadLocals两个ThreadLocal,getMap和createMap的时候操作的是线程中的inheritableThreadLocals