多线程只有一个目的:更好的利用cpu的资源
并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。
线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。
同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如简单加入@synchronized关键字。
**阻塞(Blocked)**:
- 调用join()和sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。
- 调用wait(),使该线程处于等待池(wait blocked pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool ),释放同步锁使线程回到可运行状态(Runnable)
- 对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。
Thread类中的yield方法可以让一个running状态的线程转入runnable。
- yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会,可能无效,又选择了让步的线程。
- join()在一个线程中调用other.join(),将等待other执行完后才继续本线程。
- interrupted方法其本质只是设置该线程的中断标志,真正实现线程的中断原理是:开发人员根据中断标志的具体值,来决定如何退出线程。
- stop方法会中断一个正在运行的线程
synchronized, wait, notify 是任何对象都具有的同步工具
monitor 在synchronized 范围内,监视器发挥作用
wait/notify必须存在于synchronized块,这三个关键字针对的是同一个监视器,意味着wait之后,其他线程可以进入同步块执行。
volatile 多线程的内存模型
:
main memory(主存)、working memory(线程栈)
在处理数据时,线程会把值从主存load到本地栈,完成操作后再save回去(volatile关键词的作用:每次针对该变量的操作都激发一次load and save)。
多线程包:java.util.concurrent
ThreadLocal类
,每个使用该变量的线程提供独立的变量副本,常用于用户登录控制,如记录session信息
每个Thread都持有一个TreadLocalMap类型的变量
原子类
(AtomicInteger、AtomicBoolean……)等同于synchronized,AtomicInteger.compareAndSet(int expect,int update)可实现乐观锁
Lock类
ReentrantLock
ReentrantReadWriteLock.ReadLock
ReentrantReadWriteLock.WriteLock
lock 阻塞式, trylock 无阻塞式, lockInterruptily 可打断式, 还有trylock的带超时时间版本
r.lock()或r.lockInterruptibly()
r.unlock()
ReentrantReadWriteLock,写写,写读互斥;读读不互斥。可以实现并发读的高效线程安全代码
容器类
BlockingQueue 这个queue是单向队列,特别适用于先进先出策略的一些应用场景,BlockingQueue在队列的基础上添加了多线程协作的功能,提供了阻塞接口put和take,带超时功能的阻塞接口offer和poll。put会在队列满的时候阻塞,直到有空间时被唤醒;take在队列空的时候阻塞,直到有东西拿的时候才被唤醒。用于生产者-消费者模型尤其好用,堪称神器
常见的阻塞队列有:ArrayListBlockingQueue
LinkedListBlockingQueue
DelayQueue
SynchronousQueue
ConcurrentHashMap
高效的线程安全哈希map。请对比hashTable , concurrentHashMap, HashMap
HashMap
put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象
put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象
HashMap是在bucket中储存键对象和值对象
线程池管理类ThreadPoolExecutor
corePoolSize:池内线程初始值与最小值,就算是空闲状态,也会保持该数量线程。
maximumPoolSize:线程最大值,线程的增长始终不会超过该值。
keepAliveTime:当池内线程数高于corePoolSize时,经过多少时间多余的空闲线程才会被回收。回收前处于wait状态
unit:时间单位,可以使用TimeUnit的实例,如TimeUnit.MILLISECONDS。
workQueue:待入任务(Runnable)的等待场所,该参数主要影响调度策略,如公平与否,是否产生饿(starving) 。
threadFactory:线程工厂类,有默认实现,如果有自定义的需要则需要自己实现ThreadFactory接口并作为参数传入。
有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。