通过实现网站访问计数器带你理解 轻量级锁CAS原理,还学不会算我输!!!(上)

简介: 通过实现网站访问计数器带你理解 轻量级锁CAS原理,还学不会算我输!!!(上)

一、实现网站访问计数器


1、线程不安全的做法


1.1、代码


package com.chentongwei.concurrency;
import static java.lang.Thread.sleep;
/**
 * @Description:
 * @Project concurrency
 */
public class TestCount {
    private static int count;
    public void incrCount() {
        count ++;
    }
    public static void main(String[] args) throws InterruptedException {
        TestCount testCount = new TestCount();
        // 开启五个线程
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 每个线程都让count自增100
                for (int j = 0; j < 100; j++) {
                    testCount.incrCount();
                }
            }).start();
        }
        sleep(2000);
        // 正确的情况下会输出500
        System.out.println(count);
    }
}


1.2、结果


并不一定是500,极大可能小于500。不固定。


1.3、分析


很明显上面那段程序是线程不安全的,为什么线程不安全?因为++操作其实是类似如下的两步骤,如下:


count ++;
||
// 获取count
int temp = count;
// 自增count
count = temp + 1;


很明显是先获取在自增,那么问题来了,我线程A和线程B都读取到了int temp = count;这一步,然后都进行了自增操作,其实这时候就错了因为这时候count丢了1,并发了。所以导致了线程不安全,结果小于等于500。


2、Synchronized保证线程安全


2.1、代码


package com.chentongwei.concurrency;
import static java.lang.Thread.sleep;
/**
 * @Description:
 * @Project concurrency
 */
public class TestCount {
    private static int count;
    public  void incrCount() {
        count ++;
    }
    public static void main(String[] args) throws InterruptedException {
        TestCount testCount = new TestCount();
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for (int j = 0; j < 100; j++) {
                    synchronized (TestCount.class) {
                        testCount.incrCount();
                    }
                }
            }).start();
        }
        sleep(2000);
        System.out.println(count);
    }
}


2.2、结果


500


2.3、分析


没什么可分析的,我用了Java的内置锁Synchronized来保证了线程安全性。加了同步锁之后,count自增的操作变成了原子性操作,所以最终输出一定是500。众所周知性能不好,所以继续往下看替代方案。


3、原子类保证线程安全


3.1、代码


package com.chentongwei.concurrency;
import java.util.concurrent.atomic.AtomicInteger;
import static java.lang.Thread.sleep;
/**
 * @Description:
 * @Project concurrency
 */
public class TestCount {
    // 原子类
    private static AtomicInteger count = new AtomicInteger();
    public  void incrCount() {
        count.getAndIncrement();
    }
    public static void main(String[] args) throws InterruptedException {
        TestCount testCount = new TestCount();
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for (int j = 0; j < 100; j++) {
                    testCount.incrCount();
                }
            }).start();
        }
        sleep(2000);
        System.out.println(count);
    }
}


3.2、结果


500


3.3、分析


所谓原子操作类,指的是java.util.concurrent.atomic包下,一系列以Atomic开头的包装类。如AtomicBoolean,AtomicUInteger,AtomicLong。它们分别用于Boolean,Integer,Long类型的原子性操作。每个原子类内部都采取了CAS算法来保证的线程安全性。

相关文章
|
缓存 安全 Java
【JavaSE专栏78】线程同步,控制多个线程之间的访问顺序和共享资源的安全性
【JavaSE专栏78】线程同步,控制多个线程之间的访问顺序和共享资源的安全性
108 0
|
5月前
|
Java
什么是 CAS(自旋锁)? 它的优缺点? 如何使用CAS实现一把锁?
该博客文章解释了什么是CAS(自旋锁),包括CAS的基本概念、实现原理、优缺点,以及如何使用CAS实现锁的逻辑,并提供了使用CAS实现锁的Java完整代码示例和测试结果。
什么是 CAS(自旋锁)? 它的优缺点? 如何使用CAS实现一把锁?
|
8月前
|
存储 缓存 Linux
Linux驱动开发(锁和信号量的概念及实现原理)
Linux驱动开发(锁和信号量的概念及实现原理)
136 0
|
Java API
java并发原理实战(3) -- 线程的中断和初始化
java并发原理实战(3) -- 线程的中断和初始化
237 0
java并发原理实战(3) -- 线程的中断和初始化
|
存储 安全 Java
小白也能看懂的锁升级过程和锁状态
小白也能看懂的锁升级过程和锁状态
274 0
小白也能看懂的锁升级过程和锁状态
|
数据采集 缓存 算法
库调多了,都忘了最基础的概念 《锁与线程 2 终结篇》
库调多了,都忘了最基础的概念 《锁与线程 2 终结篇》
145 0
库调多了,都忘了最基础的概念 《锁与线程 2 终结篇》
|
存储 算法 安全
通过实现网站访问计数器带你理解 轻量级锁CAS原理,还学不会算我输!!!(下)
通过实现网站访问计数器带你理解 轻量级锁CAS原理,还学不会算我输!!!(下)
通过实现网站访问计数器带你理解 轻量级锁CAS原理,还学不会算我输!!!(下)
|
存储 安全 Java
死磕synchronized二:系统剖析延迟偏向篇一
近期准备写一个专栏:从Hotspot源码角度剖析synchronized。前前后后大概有10篇,会全网发,写完后整理成电子书放公众号供大家下载。对本专栏感兴趣的、希望彻彻底底学明白synchronized的小伙伴可以关注一波。电子书整理好了会通过公众号群发告知大家。我的公众号:**硬核子牙**。
290 0
死磕synchronized二:系统剖析延迟偏向篇一
使用递增计数器的线程同步工具 —— 信号量,它的原理是什么样子的?
在 JUC 中线程同步器除了 CountDownLatch 和 CycleBarrier ,还有一个叫做 Semaphore (信号量),同样是基于 AQS 实现的。下面来看看信号量的内部原理。
130 0
什么是可中断锁?有什么用?怎么实现?(2)
什么是可中断锁?有什么用?怎么实现?(2)
315 0
什么是可中断锁?有什么用?怎么实现?(2)