使用无锁完成多线程模拟售票, 理解无锁是啥?

实现的模拟多线程实现售票是每个学习多线程的初学者必须要学会掌握的知识点, 既然掌握的它, 我们自然要举一反三

So~, 无锁版出现了

What无锁?

假如两个线程同时修改一个变量的场景下

我们需要三个值, 预期值(线程副本变量中的值), 主存值(从主存变量中的值), 新值(我们要设置的值)

如果 预期值 不等于 主存值 则忽略 新值 写入  =========> 这句话是一个原子操作, 是不可分割的(就是内存屏障), 在执行这个过程中, 是不会失去时间片的

如果 预期值 等于 主存值 则  新值 写入  =========> 这句话是一个原子操作, 是不可分割的(就是内存屏障), 在执行这个过程中, 是不会失去时间片的

直接上代码就能理解了, 这是多线程模拟售票的案例, 里面有无锁和加锁的案例

package com.zhazha.juc;

import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zhazha
 * @version 1.0.0
 * @date 2019/10/19 9:39
 * @msg
 **/
public class TestTicketAtomicLock {

    @Test
    public void test01() throws Exception {
        CountDownLatch latch = new CountDownLatch(3);
        TicketAtomic ticket = new TicketAtomic(latch);
        for (int i = 0; i < 3; i++) {
            new Thread(ticket).start();
        }
        latch.await();
    }

    @Test
    public void test() throws Exception {
        CountDownLatch latch = new CountDownLatch(3);
        TicketNonAtomic ticket = new TicketNonAtomic(latch);
        for (int i = 0; i < 3; i++) {
            new Thread(ticket).start();
        }
        latch.await();
    }

}

class TicketAtomic implements Runnable {

    private AtomicInteger ticket = new AtomicInteger(100);
    private CountDownLatch latch;

    public TicketAtomic(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        while (true) {
            try {
                int temp = ticket.get();
                if (temp > 0) {
                    // TimeUnit.MILLISECONDS.sleep(100);
                    if (ticket.compareAndSet(temp, ticket.get() - 1)) {
                        System.out.println(Thread.currentThread().getName() + " \t成功售票, 余票为: " + ticket.get());
                    }
                }
                else {
                    break;
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
        latch.countDown();
    }
}

class TicketNonAtomic implements Runnable {

    private Integer ticket = 100;
    private Lock lock = new ReentrantLock();
    private CountDownLatch latch;

    public TicketNonAtomic(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        while (true) {
            lock.lock();
            try {
                if (ticket > 0) {
                    // TimeUnit.MILLISECONDS.sleep(100);
                    System.out.println(Thread.currentThread().getName() + " \t成功售票, 余票为: " + --ticket);
                }
                else {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        latch.countDown();
    }
}

上面无锁代码中, 最重要的是这句话

if (ticket.compareAndSet(temp, ticket.get() - 1)) {

内部代码

再进去就是用c++实现的无锁

这步是原子性操作的, 整个过程

如果 预期值 不等于 主存值 则忽略 新值 写入 等于 主存值 则 写入

原文地址:https://www.cnblogs.com/bangiao/p/11703277.html

时间: 2024-08-29 14:36:28

使用无锁完成多线程模拟售票, 理解无锁是啥?的相关文章

[数据库事务与锁]详解七: 深入理解乐观锁与悲观锁

注明: 本文转载自http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性. 乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段. 无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想.其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache.hibernate.

多线程模拟售票

需求:某电影院出售某些电影的票(复联3,红高粱....),有三个窗口同时进行售票(100张票),请您设计一个程序,模拟电影院售票两种方式:继承接口(1)synchronized实现public class SellTicketDemo { public static void main(String[] args) { //创建资源类对象(共享资源类/目标对象) SellTicket st = new SellTicket() ; //创建线程类对象 Thread t1 = new Thread

java中多线程模拟(多生产,多消费,Lock实现同步锁,替代synchronized同步代码块)

import java.util.concurrent.locks.*; class DuckMsg{ int size;//烤鸭的大小 String id;//烤鸭的厂家和标号 DuckMsg(){ } DuckMsg(int size, String id){ this.size=size; this.id=id; } public String toString(){ return id + " 大小为:" + size; } } class Duck{ private int

[数据库事务与锁]详解八:底理解数据库事务乐观锁的一种实现方式——CAS

注明: 本文转载自http://www.hollischuang.com/archives/1537 在深入理解乐观锁与悲观锁一文中我们介绍过锁.本文在这篇文章的基础上,深入分析一下乐观锁的实现机制,介绍什么是CAS.CAS的应用以及CAS存在的问题等. 线程安全 众所周知,Java是多线程的.但是,Java对多线程的支持其实是一把双刃剑.一旦涉及到多个线程操作共享资源的情况时,处理不好就可能产生线程安全问题.线程安全性可能是非常复杂的,在没有充足的同步的情况下,多个线程中的操作执行顺序是不可预

IOS_多线程_售票

H:/1007/01_多线程_大任务_MainViewController.m // MainViewController.m // 多线程-01.大任务 // Created by apple on 13-10-7. #import "MainViewController.h" @interface MainViewController () @property (weak, nonatomic) UIImageView *imageView; @end @implementatio

深入理解互斥锁的实现

在实际的软件编程中,经常会遇到资源的争用,比如下面的例子: [cpp] view plaincopyprint? class Counter { private: int value; public: Counter(int c) { value = c; } int GetAndIncrement() { int temp = value; //进入危险区 value = temp +1; //离开危险区 return value; } } class Counter { private: i

多线程的一些理解

多线程:★★★★ 进程:正在进行中的程序.其实进程就是一个应用程序运行时的内存分配空间. 线程:其实就是进程中一个程序执行控制单元,一条执行路径.进程负责的是应用程序的空间的标示.线程负责的是应用程序的执行顺序. 一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序,每个线程在栈区中都有自己的执行空间,自己的方法区.自己的变量. jvm在启动的时,首先有一个主线程,负责程序的执行,调用的是main函数.主线程执行的代码都在main方法中. 当产生垃圾时,收垃

Synchronized锁性能优化偏向锁轻量级锁升级 多线程中篇(五)

不止一次的提到过,synchronized是Java内置的机制,是JVM层面的,而Lock则是接口,是JDK层面的 尽管最初synchronized的性能效率比较差,但是随着版本的升级,synchronized已经变得原来越强大了 这也是为什么官方建议使用synchronized的原因 毕竟,他是一个关键字啊,这才是亲儿子,Lock,终归差了一点 简单看下,synchronized大致都经过了哪些重要的变革 重量级锁 对于最原始的synchronized关键字,锁被称之为重量级锁 因为底层依赖监

多线程编程-- part5.1 互斥锁之公平锁-获取锁

基本概念 1.AQS:AbstractQueuedSynchronizer类 AQS是java中管理“锁”的抽象类,锁的许多公共方法都是在这个类中实现.AQS是独占锁(例如,ReentrantLock)和共享锁(例如,Semaphore)的公共父类. (01) 独占锁 -- 锁在一个时间点只能被一个线程锁占有.根据锁的获取机制,它又划分为“公平锁”和“非公平锁”.公平锁,是按照通过CLH等待线程按照先来先得的规则,公平的获取锁:而非公平锁,则当线程要获取锁时,它会无视CLH等待队列而直接获取锁.