天天看点

JAVA并发编程之基本概念

1、锁是对对象访问的时候,通过对对象加锁,防止并行访问的控制手段;对对象加锁成功,代表我持有这个对象的监视器,解锁,代表释放了这个对象的监视器。

拿到对象的监视器,肯定是对对象加锁成功的;对对象加锁成功 ,程序可以主动Watiing或者Time_waiting在对象监视器上。

2、锁与监视器区别

参见以下文章 Java锁和监视器  java-jvm-jstack-(监视器和锁的概念) Synchronized的内部实现原理

3、同步队列与等待队列

简单的理解是同步队列存放着竞争同步资源的线程的引用(不是存放线程),而等待队列存放着待唤醒的线程的引用。

在Object的监视器模型中,一个对象拥有一个同步队列和一个等待队列,而并发包中的Lock(更确切的说是同步器AQS)拥有一个同步队列和多个等待队列。

JAVA并发编程之基本概念

4、非公平锁和公平锁

公平锁模式,是根据FIFO规则,在同步队列中,依据线程等待锁的时间长短,也就是头结点的下一个节点获取到锁。

非公平锁模式,一个线程在释放锁之后,ReentrantLock类从同步队列中怎么决定哪个线程可以获取到锁的?非公平锁的非公平体性体现在一个线程会首先尝试获取同步状态,不管同步队列是否有线程在排队,这就有可能在其他线程释放锁后,当前线程比同步队列中的线程先获取到锁。

以Semaphore类说明:
1、//非公平锁,在获取同步状态时,直接尝试获取同步状态,如果获取同步状态成功,则获取到锁。注意,非公平锁的线程并没有判断当前同步队列是否有节点。
final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
2、//公平锁,在获取同步状态时,先判断当前同步队列是否有节点,如果有存在等待的节点,则返回-1,表示获取锁失败
protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())//查询是否有线程正在等待获取锁。
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
           

5、自旋锁

自旋锁:线程获取锁的时候,如果锁被其他线程持有,则当前线程将循环等待,直到获取到锁。

6、happen-before规则

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;参考这里:java 8大happen-before原则超全面详解
  • 锁定规则:一个unLock操作先行发生于后面对同一个锁的lock操作;
  • volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作; 对一个 volatile 变量的读,总是能看到(任意线程)对这个 volatile 变量最后的写入。关于volatile变量的,很重要,看这里: volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
  • 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;
  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;

7、偏向锁,轻量级锁,重量级锁

     偏向锁:偏向锁是一种针对加锁操作的优化手段。它的核心思想是:如果一个线程获得了锁,那么锁就进入偏向模式。当这个线程再次请求锁时,无须再做任何同步操作。  

     轻量级锁:轻量级锁是相对于重量级锁而言的,而重量级锁就是传统的锁。轻量级锁是一种乐观锁,它认为锁存在竞争的概率比较小,所以它不使用互斥同步,而是使用CAS操作来获得锁,这样能减少互斥同步所使用的互斥量带来的性能开销。

    重量级锁: 重量级锁是一种悲观锁,它认为总是有多条线程要竞争锁,所以它每次处理共享数据时,不管当前系统中是否真的有线程在竞争锁,它都会使用互斥同步来保证线程的安全。    

    锁升级:参考这个文章,写的不错。Java并发——Synchronized关键字和锁升级,详细分析偏向锁和轻量级锁的升级

继续阅读