CAS

java高并发系列

生来就可爱ヽ(ⅴ<●) 提交于 2020-04-22 07:18:36
这是java高并发系列第21篇文章。 本文主要内容 从网站计数器实现中一步步引出CAS操作 介绍java中的CAS及CAS可能存在的问题 悲观锁和乐观锁的一些介绍及数据库乐观锁的一个常见示例 使用java中的原子操作实现网站计数器功能 我们需要解决的问题 需求:我们开发了一个网站,需要对访问量进行统计,用户每次发一次请求,访问量+1,如何实现呢? 下面我们来模仿有100个人同时访问,并且每个人对咱们的网站发起10次请求,最后总访问次数应该是1000次。实现访问如下。 方式1 代码如下: package com.itsoku.chat20; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * 跟着阿里p7学并发,微信公众号:javacode2018 */ public class Demo1 { //访问次数 static int count = 0; //模拟访问一次 public static void request() throws InterruptedException { //模拟耗时5毫秒 TimeUnit.MILLISECONDS.sleep(5); count++; } public static void main(String[]

【并发编程】并发编程中你需要知道的基础概念

会有一股神秘感。 提交于 2020-04-22 05:38:23
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 多线程是Java编程中一块非常重要的内容,其中涉及到很多概念。这些概念我们平时经常挂在嘴上,但是真的要让你介绍下这些概念,你可能还真的讲不清楚。这篇博客就总结下多线程编程中经常用到的概念,理解这些概念能帮助我们更好地掌握多线程编程。 进程(Process)与线程(Thread) 进程和线程是最常提到的概念了。在linux中,线程与进程最大的区别就是是否共享同一块地址空间,而且共享同一块地址空间的那一组线程将显现相同的PID号。下面介绍下两者的概念: 进程是操作系统进行资源分配和调度的最小单元,可以简单地理解为系统中运行的一个程序就是一个进程。 线程是CPU调度的最小单元,是进程中的一个个执行流程。 一个进程至少包含一个线程,可以包含多个线程,这些线程共享这个进程的资源(比如堆区和方法区资源)。同时每个线程都拥有独立的运行栈和程序计数器,线程切换开销小。 多进程指的是操作系统同时运行多个程序,如当前操作系统中同时运行着QQ、IE、微信等程序。 多线程指的是同一进程中同时运行多个线程,如迅雷运行时,可以开启多个线程,同时进行多个文件的下载。 谈到线程和进程,又势必会涉及到线程号和进程号的概念。下面列举了各个ID的概念。 pid: 进程ID。

多线程学习笔记五之读写锁实现分析

笑着哭i 提交于 2020-04-22 05:31:19
[TOC] 简介   在前一篇博客 多线程学习笔记三之ReentrantLock与AQS实现分析 分析了基于同步器AQS实现的独占锁ReentrantLock,AQS同步器作为JUC组件实现锁的框架,基于AQS除了可以实现独占锁,还可以实现共享锁。   ReentrantReadWriteLock是基于AQS实现的读写锁,内部维护了一个读锁(共享锁)和写锁(独占锁)。如果我们要在程序中提供共享的缓存数据结构,缓存肯定是读操作(数据查询)多而写操作(数据更新)少,只要保证写操作对后续的读操作是可见的就行了,这种情况下使用独占锁就不如读写锁的吞吐量大,读写锁中的读锁允许多个线程获得读锁对资源进行读操作,写锁是传统的独占锁,只允许单个线程获得写锁对资源进行更新。以下是JDK提供基于ReentrantReadWriteLock简单实现缓存结构的Demo: class CachedData { Object data; volatile boolean cacheValid; final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); void processCachedData() { rwl.readLock().lock(); if (!cacheValid) { // 必须先释放读锁再获取写锁 rwl

J.U.C剖析与解读1(Lock的实现)

假如想象 提交于 2020-04-22 05:31:01
J.U.C剖析与解读1(Lock的实现) 前言 为了节省各位的时间,我简单介绍一下这篇文章。这篇文章主要分为三块:Lock的实现,AQS的由来(通过演变的方式),JUC三大工具类的使用与原理剖析。 Lock的实现:简单介绍ReentrantLock,ReentrantReadWriteLock两种JUC下经典Lock的实现,并通过手写简化版的ReentrantLock和ReentrantReadWriteLock,从而了解其实现原理。 AQS的由来:通过对两个简化版Lock的多次迭代,从而获得AQS。并且最终的Lock实现了J.U.C下Lock接口,既可以使用我们演变出来的AQS,也可以对接JUC下的AQS。这样一方面可以帮助大家理解AQS,另一方面大家可以从中了解,如何利用AQS实现自定义Lock。而这儿,对后续JUC下的三大Lock工具的理解有非常大的帮助。 JUC三大工具:经过前两个部分的学习,这个部分不要太easy。可以很容易地理解CountDownLatch,Semaphore,CyclicBarrier的内部运行及实现原理。 不过,由于这三块内容较多,所以我将它拆分为三篇子文章进行论述。 一,介绍 Lock Lock接口位于J.U.C下locks包内,其定义了Lock应该具备的方法。 Lock 方法签名: void lock():获取锁(不死不休,拿不到就一直等)

java高并发系列

僤鯓⒐⒋嵵緔 提交于 2020-04-22 05:18:27
这是java高并发系列第22篇文章,文章基于jdk1.8环境。 本文主要内容 基本介绍 通过反射获取Unsafe实例 Unsafe中的CAS操作 Unsafe中原子操作相关方法介绍 Unsafe中线程调度相关方法 park和unpark示例 Unsafe锁示例 Unsafe中保证变量的可见性 Unsafe中Class相关方法 示例:staticFieldOffset、staticFieldBase、staticFieldBase 示例:shouldBeInitialized、ensureClassInitialized 对象操作的其他方法 绕过构造方法创建对象 数组相关的一些方法 内存屏障相关操作 java高并发系列目录 基本介绍 最近我们一直在学习java高并发,java高并发中主要涉及到类位于java.util.concurrent包中,简称juc,juc中大部分类都是依赖于Unsafe来实现的,主要用到了Unsafe中的CAS、线程挂起、线程恢复等相关功能。所以如果打算深入了解JUC原理的,必须先了解一下Unsafe类。 先上一幅Unsafe类的功能图: Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用

AQS系列(三)- ReentrantReadWriteLock读写锁的加锁

為{幸葍}努か 提交于 2020-04-22 05:12:29
前言 前两篇我们讲述了ReentrantLock的加锁释放锁过程,相对而言比较简单,本篇进入深水区,看看ReentrantReadWriteLock-读写锁的加锁过程是如何实现的,继续拜读老Lea凌厉的代码风。 一、读写锁的类图 读锁就是共享锁,而写锁是独占锁。读锁与写锁之间的互斥关系为: 读读可同时执行(有条件的);读写与写写均互斥执行 。注意此处读读可并行我用了有条件的并行,后文会对此做介绍。 继续奉上一张丑陋的类图: 可以看到ReentrantReadWriteLock维护了五个内部类,ReentrantReadWriteLock中存放了Sync、ReadLock、WriteLock三个成员变量,如下截图所示: 而ReadLock和WriteLock中又存放了Sync变量,截图如下所示,这样一组合,有了四种锁,公平读锁、公平写锁、非公平读锁、非公平写锁。对于公平与非公平的实现区别,我们上一篇已经做过讲解,本文将着重关注读锁和写锁的实现区别。 二、加锁源码 在前文中我们知道,ReentrantLock中用state来判断当前锁是否被占用,而读写锁ReentrantReadWriteLock中由于同时存在两种锁,所以老Lea用state的高16位来存放读锁的占用状态以及重入次数,低16位存放写锁的占用状态和重入次数。 1、读锁加锁,即共享锁加锁 1 public void

java高并发系列

情到浓时终转凉″ 提交于 2020-04-22 03:47:12
这是java高并发系列第25篇文章。 环境:jdk1.8。 本文内容 掌握Queue、BlockingQueue接口中常用的方法 介绍6中阻塞队列,及相关场景示例 重点掌握4种常用的阻塞队列 Queue接口 队列是一种先进先出(FIFO)的数据结构,java中用 Queue 接口来表示队列。 Queue 接口中定义了6个方法: public interface Queue<E> extends Collection<E> { boolean add(e); boolean offer(E e); E remove(); E poll(); E element(); E peek(); } 每个 Queue 方法都有两种形式: (1)如果操作失败则抛出异常, (2)如果操作失败,则返回特殊值( null 或 false ,具体取决于操作),接口的常规结构如下表所示。 操作类型 抛出异常 返回特殊值 插入 add(e) offer(e) 移除 remove() poll() 检查 element() peek() Queue 从 Collection 继承的 add 方法插入一个元素,除非它违反了队列的容量限制,在这种情况下它会抛出 IllegalStateException ; offer 方法与 add 不同之处仅在于它通过返回 false 来表示插入元素失败。 remove 和

线程同步(互斥锁与信号量的作用与区别)

主宰稳场 提交于 2020-04-21 16:21:10
摘自: https://www.cnblogs.com/alinh/p/6905221.html “信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在 哪里)。而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这 个资源。比如对全局变量的访问,有时要加锁,操作完了,在解锁。有的时候锁和信号量会同时使用的” 也就是说,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤,这个任务 并不一定是锁定某一资源,还可以是进行一些计算或者数据处理之类。而线程互斥量则是“锁住某一资源”的概念,在锁定期间内,其他线程无法对被保护的数据进 行操作。在有些情况下两者可以互换。 两者之间的区别: 作用域 信号量: 进程间或线程间(linux仅线程间的无名信号量pthread semaphore) 互斥锁: 线程间 上锁时 信号量: 只要信号量的value大于0,其他线程就可以sem_wait成功,成功后信号量的value减一。若value值不大于0,则sem_wait使得线程阻塞,直到sem_post释放后value值加一,但是sem

ReentrantLock详解

旧时模样 提交于 2020-04-21 07:12:47
ReentrantLock概述 ReentrantLock是Lock接口的实现类,可以手动的对某一段进行加锁。 ReentrantLock可重入锁,具有可重入性,并且支持可中断锁。其内部对锁的控制有两种实现,一种为公平锁,另一种为非公平锁。 ReentrantLock的实现原理为 volatile+CAS 。 ReentrantLock可重入性 ReentrantLock具有可重入性,可重入性是指当一个线程拥有一个方法的锁以后,是否还可以进入该方法,一般这种情况出现在递归中。ReentrantLock的可重入性是基于Thread.currentThread()实现的,是线程粒度的,也就是说当前线程获得一个锁以后,当前线程的所有方法都可以获得这个锁。Reentrant依赖的锁只有两种实现类, NonFairSync 和 FairSync ,但是它们 获取锁 的方式大同小异。一下是公平锁的获取实现。 ReentrantLock . FairSync .tryAcquire 1 protected final boolean tryAcquire( int acquires) { 2 final Thread current = Thread.currentThread(); 3 int c = getState(); 4 // 每一次加锁state+1 5 if (c == 0 ) {

Spring IOC 容器源码分析

十年热恋 提交于 2020-04-21 06:27:16
1. 简介 本篇文章是“Spring IOC 容器源码分析”系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bean 做最后的初始化工作。相较于之前几篇文章所分析的源码,initializeBean 的源码相对比较简单,大家可以愉快的阅读。好了,其他的不多说了,我们直入主题吧。 2. 源码分析 本章我们来分析一下 initializeBean 方法的源码。在完成分析后,还是像往常一样,把方法的执行流程列出来。好了,看源码吧: protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { // 若 bean 实现了