对象锁

大多数类都将内置锁作为一种有效的加锁机制,但是对象的域并不一定要通过内置锁来保护,之所以每个对象都有一个内置锁,只是为了免去显示的创建锁对象.

自旋锁

当互斥同步的时候(悲观锁),互斥同步对性能影响最大的就是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性带来了很大的压力。同时,在实际应用中,共享数据的锁定状态只会持续很短的一断时间,为了让这段时间去恢复和挂起线程并不值得,如果物理机器有一个以上处理器,能让两个线程同时并行执行,就可以让后面请求锁的那个线程稍等一下,但不放弃处理器的执行时间,看看持有锁的线程是否很快的会释放锁。为了让线程等待,我们需要让线程执行一个忙循环(自旋)这就是自旋锁。

自旋等待本身虽然避免了线程切换的开销,但是是要占用处理器时间的,因此。如果锁占用时间很短,则效果很好,反之,锁占用时间很长,自旋就会白白消耗处理器资源,带来性能上的浪费。

jdk1.6引入了自适应的自旋锁,意味着自旋的时间不再苦丁,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。

监视器锁

Java中实现同步的一种机制就是利用Synchronized关键字来修饰同步代码块,他的本质是对对象进行枷锁来达到同步的目的,称这种锁为对象监视器锁。

根据java虚拟机规范,被synchronized关键字修饰的代码块在被编译成字节码的时候 会在该代码块开始和结束的时候插入monitorenter 和 moniterexist指令,虚拟机在执行这两个指令的时候会检查对象的锁状态是否为空或当前线程是否已经拥有该对象锁 如果是 则将对象锁的计数器加1 直接进入同步代码执行。如果不是当前线程就要阻塞等待 等到锁释放 。

java的线程是映射到OS原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统的帮忙,这就要从用户态转换到核心态,因此状态转换需要花费很多的处理器时间,对于代码简单的同步块(如被synchronized修饰的get 或set方法)状态转换消耗的时间有可能比用户代码执行的时间还要长,所以说synchronized是java语言中一个重量级的操纵。

Daemon线程

有时候,你希望创建一个线程来执行一些辅助工作,但是又不希望这个线程阻碍JVM的关闭,这种情况下就需要使用守护线程。

线程可以分为两种,普通线程和守护线程。在JVM启动时创建的所有线程中,除了主线程以外,其他的线程都是守护线程(例如垃圾回收器以及其他执行辅助工作的线程)当创建一个新线程时,新线程将继承创建它的线程的守护状态,因此在默认情况下,主线程创建的所有线程都是普通线程。

普通线程与守护线程的区别仅在于当线程退出时发生的操作,当一个线程退出时,JVM会检查其他正在运行的线程,如果这些线程都是守护线程,那么JVM就会正常退出,当JVM停止时,所有守护线程既不会执行finally,也不会执行回卷栈,而JVM只是直接退出。

Fork/join

分而治之是有效处理大量数据的方法,

fork有分叉的意思,也就是创建子进程, join表示等待

实际使用线程池执行的时候,一个物理线程需要处理多个逻辑任务,因此,一个线程必然要拥有一个任务队列,因此,线程A可能执行完了自己的任务,线程B还有一堆任务等着执行,这时,A就会帮助B.从B的任务队列中拿过来任务帮助B

需要注意的是,当线程试图帮助别人的时候,总是从任务队列的底部开始拿数据,而线程执行自己的任务时,总是从顶部拿数据

ForkJoinPool的一个重要接口

1
public <T> ForkJoinTask<T> submit (ForkJoinTask<T> task)

可以向forkJoinPool线程池提交一个ForkJoinTask任务,ForkJoinTask任务就是支持fork分解和join等待的任务,