线程状态
NEW 未运行新线程
RUNNABLE 运行中
BLOCKED 阻塞
WAITING 等待
TIMED_WAITING 超时等待
TERMINATED 结束
创建线程的3总方式
继承Thread
1.直接start运行线程
实现Runnable接口
1.Thread传入Runnable运行线程
实现Callable接口
1.Thread传入FutureTask(Callable<返回值类型>)运行线程
2.有返回值,future.get() 如果call()方法没有执行完成,则阻塞等待
等待线程执行完毕,让出当前线程执行权,线程睡眠
join
等待运行线程执行终止后,继续执行 。默认无参传0代表没有超时时间,thread类join()方法实际调用了object类wait ()方法
public final void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException #等待超时时间
public final synchronized void join(long millis, int nanos) throws InterruptedException #nanos 纳秒级控制
yield
是让出执行权,本身还处于就绪状态,不释放锁
sleep
暂时让出执行权,进入阻塞状态,不参与CPU调度,不释放锁。时间到了则继续执行。
public static native void sleep(long millis) throws InterruptedException #睡眠时间
public static void sleep(long millis, int nanos) throws InterruptedException # nanos 纳秒级控制
thread.interrupt() #线程中断标记可打断sleep睡眠
线程安全
线程安全线程把主内存值拿到工作内存产生运行。由多个线程对全局变量和静态变量进行写操作,产生线程不安全 (脏读)
volatile
修饰的变量不会存储在线程的工作内存区内,内存独一份,所有线程从主内存读取。volatile无法保证原子性,不保证唯一性,多实例
static
修饰变量保证唯一性,多个实例共享一个,只有一个实例,推荐用静态内部类方式创建,静态类使用时才加载内部静态资源
Atomic (java.util.concurrent.*)
AtomicInteger sum = new AtomicInteger #acomic类变量提供原子性,原子类 ,无锁 ,CAS操作,每次修改携带版本号,当版本号不一致的循环从新获取版本号。
AtomicStampedReference #解决CAS的ABA问题
AtomicStampedReference<Integer> atomic = new AtomicStampedReference<>(10, 0)
atomic.compareAndSet(10, 11, atomic.getStamp(), atomic.getStamp() + 1)
ThreadLocal
ThreadLocal<Integer> #为每个线程在共享内存区创建独立的副本,线程各自用自己的副本
InheritableThreadLocal<Integer> tl = new InheritableThreadLocal<>() # 同级线程之间读取副本, 父子线程之间复制传递,子线程初始化时读取父线程的ThreadLocal
InheritableThreadLocal 可以做链路追踪,记录用户id日志等
同步容器
ConcurrentHashMap #把整个容器片段分为16个分区16把锁 ,线程安全 #替换 HashMap、HashTable
ConcurrentSkipListMap # 替换 TreeMap 有序。
CopyOnWriteArrayList #读写分离, 写入时加锁将容器进行Copy出新容器,在新容器中进行写入操作 ,最后将原容器的引用指向新容器,
并发读取入时,无锁无影响。但有弱一致性问题,Iterator迭代器快照数据可能不准。 #替换ArrayList() ,合适读多写少。
CopyOnWriteArraySet #替换HashSet() ,基于CopyOnWriteArrayList ,无序,无重复
ConcurrentSkipListSet # 替换 TreeSet() ,基于CopyOnWriteArrayList ,有序,无重复
使用以下方法被包裹的类将支持线程安全,
Collections.synchronizedCollection(c); Collections.synchronizedList(list); Collections.synchronizedMap(m);
Collections.synchronizedSet(s); Collections.synchronizedSortedMap(m); Collections.synchronizedSortedSet(s);
CAS底层
Unsafe
通过反射获取Unsafe
theUnsafeField field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
获取元素偏移地址
1. objectFieldOffset 获取字段偏移地址
2. staticFieldOffset 获取静态字段偏移地址
3. arrayBaseOffset 获取数组中第一个元素的地址
4. arrayIndexScale 获取数组中一个元素占用的字节
休眠
unsafe.park(false,2000*1000000); #非绝对时间为纳秒
unsafe.park(true,System.currentTimeMillis()+2000); #绝对时间为毫秒
唤醒
unsafe.unpark(t);
t.interrupt(); # 标记线程中断状态也可以唤醒 ,但不抛出异常 需要自行判断
if(Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName()+"-interrupte" );
}
AbstractQueuedSynchronizer AQS
守护线程与用户线程
daemon线程(守护线程)、user线程(用户线程)
全部user线程结束时,JVM会正常退出
用户线程:当存在任何一个用户线程未离开,JVM是不会离开的。
守护线程:如果只剩下守护线程未离开,JVM是可以离开的。
thread.setDaemon(true); #设置当前线程为守护线程