线程类:
1.start是在主线程执行,run是新开启一个线程执行
2. synchronized是对类的当前实例进行加锁,static synchronized是对类进行加锁.
pulbic class Something(){
public synchronized void isSyncA(){}
public synchronized void isSyncB(){}
public static synchronized void cSyncA(){}
public static synchronized void cSyncB(){}
}
x.isSyncA()与Static.classSyncA()不互相影响.
3.yield()是做线程让步,把锁让出来,和其他线程一起继续竞争资源.
4.join()让主线程等待子线程执行完毕之后才继续进行.
5.interrupt()中断本线程.如果这个线程处于阻塞状态,isInterrupted会返回true,会抛出InterruptedException,如果处于运行状态,调用interrupt()只是重置标志位为false,并抛出异常.
每个线程都有一个与之相关联的 Boolean 属性,用于表示线程的中断状态(interrupted status)。中断状态初始时为 false;
concurrent:
基于cas机制(compare and swap).基于硬件级别的控制.如果CAS有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做并返回false
集合:
hashmap:key和value都可以为null.底层是数组加链表实现的. loadFactor默认是0.75,size默认是16,每次resize size都翻倍,然后所有值再hash分配.遍历的时候entrySet效率比keySet高.
因为每个entry节点保存的是链表,顺序访问,如果用keyset,首先得找到key,key又是保存在链表中的,遍历速度很慢.jdk1.8中如果链表节点数量大于8,转换成红黑树.
hashset:底层是hashmap实现的.
hashTable:HashTable默认的初始大小为11,之后每次扩充为原来的2n+1.
linkedhashMap:底层也是hashmap的实现,不过添加了Entry类型的header,tail的变量用来当作链表记录添加顺序,如果accessOrder标记为true,那么会按访问顺序排序.
TreeMap:底层是红黑树实现的.按key比较存放的,所以是有序的.
linkedhashSet:底层是linkedhashMap实现的.
concurrentMap:
jdk1.7之前使用segment
进行put操作的时候会先找到你属于那个segment对象,然后在segment对象的put方法里再hash寻找属于hashEntry[]数组的哪个位置.
jdk1.8取消了segments对象,而是直接用Node
copyOnWriteArrayList: 内部结构也是用数组实现,不过加了修饰符volatile,增加删除操作都会加锁.遍历的时候只会遍历副本,所以是线程安全的.
copyOnWriteArraySet:底层是copyOnWriteArrayList实现的.
ConcurrentSkipListMap:数据结构如下图所示.跳表分为许多层(level),每一层都可以看作是数据的索引,这些索引的意义就是加快跳表查找数据速度。每一层的数据都是有序的,上一层数据是下一层数据的子集,并且第一层(level 1)包含了全部的数据;层次越高,跳跃性越大,包含的数据越少。跳表包含一个表头,它查找数据时,是从上往下,从左往右进行查找.底层通过cas来实现线程安全.
ArrayBlockingQueue:数组实现的线程安全的有界的阻塞队列,底层是数组,通过ReentrantLock和Condition来实现.put方法会阻塞,offer会返回true或者false,add通过offer实现,offer返回false抛出异常.
LinkedBlockingQueue:LinkedBlockingQueue是一个单向链表实现的阻塞队列。该队列按 FIFO(先进先出)排序元素,新元素插入到队列的尾部,并且队列获取操作会获得位于队列头部的元素。它对头和尾(取和添加操作)采用两把不同的锁,所以吞吐量通常要高于基于数组的队列.
LinkedBlockingDeque:LinkedBlockingDeque是双向链表实现的双向并发阻塞队列。该阻塞队列同时支持FIFO和FILO两种操作方式,即可以从队列的头和尾同时操作(插入/删除)
ConcurrentLinkedQueue:通过 cas来实现线程安全的队列.
PriorityBlockingQueue:优先级阻塞队列,底层也是通过数组加ReentrantLock实现的,存入的数据用二分法排序插入来实现优先级.
锁 :
ReentrantLock:
通过CAS来对计算加1,如果其他线程要获取锁,计数器>1,那么就进入等待队列.
在同一个时间点只能被一个线程锁持有;而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取.ReentraantLock是通过一个FIFO的等待队列来管理获取该锁所有线程的.ReentrantLock中,包含了Sync对象;而且,Sync是AQS的子类;更重要的是,Sync有两个子类FairSync(公平锁)和NonFairSync(非公平锁)。ReentrantLock是一个独占锁,至于它到底是公平锁还是非公平锁,就取决于sync对象是"FairSync的实例"还是"NonFairSync的实例"。其它获取失败的线程会进入等待队列,直到被自己中断.
Condition:Condition的作用对锁进行更精确的控制.Condition类似Object对象.不过能进行更精确的控制.
Object Condition 休眠 wait await 唤醒个线程 notify signal 唤醒所有线程 notifyAll signalAll
//一个lock能分出多个Condition,所以可以更精确的控制.
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
LockSupport: LockSupport.park(Thread) ,unpark(Thread).和Thread.wait()的区别在于wait让线程阻塞前,必须通过synchronized获取同步锁.
CountDownLatch:先latch.await()阻塞,等待调用足够次数的countDown()之后会唤醒进程.
初始化的时候会初始化参数
CyclicBarrier:让多少个线程或者任务等待至barrier状态,才会继续执行.
Semaphore:总共有特定数量的资源,多个线程共同使用,如果资源不足会一直阻塞.
jdk线程池架构:
HashSet
-- 如果此时,线程池中运行的线程数量< corePoolSize,则创建新线程来处理请求。
-- 如果此时,线程池中运行的线程数量> corePoolSize,但是却< maximumPoolSize;则仅当阻塞队列满时才创建新线程。
线程池有四种状态:RUNNING,SHUTDOWN, STOP, TIDYING, TERMINATED
线程池被一旦被创建,就处于RUNNING状态,
调用shutdown之后变成shutdown状态,未执行完的任务继续执行,执行完之后变成tidyinng状态
调用shutdownNow之后变成stop状态 ,中断未处理完的任务,中断之后变成tidyinng状态
tidyinn状态调用terminal之后变成terminal状态.
线程池共包括4种拒绝策略,它们分别是:AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy和DiscardPolicy
AbortPolicy -- 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。
CallerRunsPolicy -- 当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。
DiscardOldestPolicy -- 当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
DiscardPolicy -- 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。
ScheduledThreadPoolExecutor的性能要优于Timer,因为timer是单线程执行的.Timer类的调度是基于绝对的时间的,而不是相对的时间,因此Timer类对系统时钟的变化是敏感的