多线程

线程状态


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 atomic = new AtomicStampedReference<>(10, 0)

atomic.compareAndSet(10, 11, atomic.getStamp(), atomic.getStamp() + 1)

ThreadLocal

ThreadLocal    #为每个线程在共享内存区创建独立的副本,线程各自用自己的副本 

InheritableThreadLocal 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);  #设置当前线程为守护线程

你可能感兴趣的:(多线程)