VariousLock

公平锁和非公平锁

公平锁

/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;

final void lock() {
acquire(1);
}

/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 是否有线程在等待
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}

非公平锁

/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;

/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}

protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}

/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}

区别:

  • 非公平锁在调用lock后,首先就会调用CAS进行一次抢锁,如果这个时候恰巧锁没有被占用,则直接获取到锁返回;

  • 非公平锁CAS抢锁失败后,会和公平锁一样进入到tryAcquire(),在tryAcquire()中,如果发现锁这个时候被释放了(state == 0),非公平锁会直接CAS抢锁,但是公平锁会判断等待队列是否有线程处于等待状态,如果有则不去抢锁,排到后面;

如果非公平锁两次CAS都不成功,后面非公平锁和公平锁是一样的,都要进入到阻塞队列等待唤醒。

相对来说,非公平锁性能更好,吞吐量更大,因为非公平锁减少了线程挂起的几率,后来的线程有一定几率逃离被挂起的开销,但会使阻塞队列中的线程长期处于饥饿状态。

乐观锁和悲观锁

乐观锁

拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间数据有没有被修改过,可以使用版本号等机制。乐观锁适用于多读的应用类型,提高吞吐量。数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

悲观锁

每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java里面的Synchronized关键字的实现也是悲观锁。

存在的问题:

  • 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
  • 一个线程持有锁会导致其它所有需要此锁的线程挂起;
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险;

synchronized

synchronized

Java多线程的锁都是基于对象的,Java中的每一个对象都可以作为一个锁。

还有一点需要注意的是,我们常听到的类锁其实也是对象锁。

Java类只有一个Class对象(可以有多个实例对象,多个实例共享这个Class对象),而Class对象也是特殊的Java对象。所以我们常说的类锁,其实就是Class对象的锁。

Read more
volatile

volatile

JMM

JMM的抽象:主内存和本地内存

JMM抽象示意图

Read more
springframework
  1. 项目导入IDEA

    环境:Windows,JDK8,Gradle 6.5.1,IDEA 2020.1.3

    • 进入 https://github.com/spring-projects/spring-framework,选择版本5.2.X,下载zip或clone到本地;

    • 编辑项目目录下的build.gradle,全局搜索allprojects,编辑其repositories属性,配置阿里云镜像,如下:

      repositories {
      maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
      maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
      mavenCentral()
      maven { url "https://repo.spring.io/libs-spring-framework-build" }
      }
    • 进入项目根目录下,预编译spring-oxm,在命令行中执行:

      gradlew :spring-oxm:compileTestJava

      (需耐心等待3-5分钟左右…) 成功后打印BUILD SUCCESSFUL

    • 导入项目至idea;

    • 移除spring-aspects模块;

Read more
basicconcurrency
  1. 进程和线程的区别

    进程是一个独立的运行环境,而线程是在进程中执行的一个任务。他们两个本质的区别是是否单独占有内存地址空间及其它系统资源(比如I/O):

    • 进程单独占有一定的内存地址空间,所以进程间存在内存隔离,数据是分开的,数据共享复杂但是同步简单,各个进程之间互不干扰;而线程共享所属进程占有的内存地址空间和资源,数据共享简单,但是同步复杂。
  • 进程单独占有一定的内存地址空间,一个进程出现问题不会影响其他进程,不影响主程序的稳定性,可靠性高;一个线程崩溃可能影响整个程序的稳定性,可靠性较低。

    • 进程单独占有一定的内存地址空间,进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大;线程只需要保存寄存器和栈信息,开销较小。
  • 另外一个重要区别是,进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位,即CPU分配时间的单位 。

Read more
Lcof39

Lcof 39.数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

​ 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
​ 输出: 2

Read more