1.使用Unsafe类

import sun.misc.Unsafe;

class UnsafePackage {
private static Unsafe unsafe; static {
try {
Class<Unsafe> unsafeClass = Unsafe.class;
Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
} catch (Exception ex) {
ex.printStackTrace();
}
} public static Unsafe getUnsafe() {
return unsafe;
}
}

2.声明简单锁

class CustomLock {
private volatile int status; private static Unsafe unsafe = UnsafePackage.getUnsafe();
private static long statusOffset;
private WaitingQueue queue = new WaitingQueue(); static {
try {
statusOffset = unsafe.objectFieldOffset(CustomLock.class.getDeclaredField("status"));
} catch (Exception ex) {
ex.printStackTrace();
}
} private boolean comareAndSetStatus(int originalStatus, int updateStatus) {
return unsafe.compareAndSwapInt(this, statusOffset, originalStatus, updateStatus);
} public boolean lock() {
if (comareAndSetStatus(0, 1)) {
//System.out.println("竞争锁成功!继续执行后面的代码");
return true;
} //System.out.println("竞争锁失败!进入等待队列");
push(Thread.currentThread());
while (!comareAndSetStatus(0, 1)) {
UnsafePackage.getUnsafe().park(false, 0);
}
return true;
} public boolean unlock() {
status = 0;
Thread thread = pop();
if (thread != null) {
UnsafePackage.getUnsafe().unpark(thread);
}
return true;
} private void push(Thread thread) {
queue.push(thread);
} private Thread pop() {
return queue.pop(); }
}

3.竞争锁失败的进队列

class WaitingQueue {
private volatile int status;
private static long statusOffset; /**
* 非线程安全,使用时,也要加锁
*/
private LinkedList<Thread> queue = new LinkedList<>(); static {
try {
statusOffset = UnsafePackage.getUnsafe().objectFieldOffset(WaitingQueue.class.getDeclaredField("status"));
} catch (Exception ex) {
ex.printStackTrace();
}
} public void push(Thread thread) {
while (!comareAndSetStatus(0, 1)) { }
queue.offerLast(thread);
comareAndSetStatus(1, 0);
return;
} public Thread pop() {
while (!comareAndSetStatus(0, 1)) { }
Thread elem = null;
if (!queue.isEmpty()) {
elem = queue.pop();
}
comareAndSetStatus(1, 0);
return elem;
} private boolean comareAndSetStatus(int originalStatus, int updateStatus) {
return UnsafePackage.getUnsafe().compareAndSwapInt(this, statusOffset, originalStatus, updateStatus);
}
}

3.调用如下

public class CustomLockTest {

    private static int count = 0;

    public static void main(String[] args) throws InterruptedException {
int threadCount = 1500;
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
CustomLock lock = new CustomLock();
long start = System.currentTimeMillis();
IntStream.range(0, threadCount)
.forEach(p -> {
new Thread() {
@Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 1000; i++) {
count++;
}
countDownLatch.countDown();
} finally {
lock.unlock();
}
}
}.start();
}); countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println("结果值为:" + count + ",共花费了" + (end - start) + "毫秒!");
}
}
结果值为:1500000,共花费了601毫秒!

使用Unsafe来实现自定义锁的更多相关文章

  1. 【腾讯Bugly干货分享】浅谈Android自定义锁屏页的发车姿势

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57875330c9da73584b025873 一.为什么需要自定义锁屏页 锁屏 ...

  2. 浅谈 Android 自定义锁屏页的发车姿势

    作者:blowUp,原文链接:http://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=2653577446&idx=2&sn= ...

  3. 重新想象 Windows 8.1 Store Apps (92) - 其他新特性: CoreDispatcher, 日历, 自定义锁屏系列图片

    [源码下载] 重新想象 Windows 8.1 Store Apps (92) - 其他新特性: CoreDispatcher, 日历, 自定义锁屏系列图片 作者:webabcd 介绍重新想象 Win ...

  4. 浅谈Android自定义锁屏页的发车姿势

    一.为什么需要自定义锁屏页 锁屏作为一种黑白屏时代就存在的手机功能,至今仍发挥着巨大作用,特别是触屏时代的到来,锁屏的功用被发挥到了极致.多少人曾经在无聊的时候每隔几分钟划开锁屏再关上,孜孜不倦,其酸 ...

  5. 模仿ReentrantLock类自定义锁

    简介 临近过年了,没什么需求,今天模仿ReentrantLock自定义写了一个自己锁,在这里记录一下,前提是对AQS原理有所了解,分享给大家 1.自定义锁MyLock package com.jack ...

  6. 自定义锁屏图片 win7

    win + R打开运行对话框 输入Regedit 点确定 进入注册表,找到以下项次 HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersi ...

  7. 005-多线程-锁-JUC锁-LockSupport【使用、Unsafe、对比Object的wait、底层源码】

    一.概述 在Java多线程中,当需要阻塞或者唤醒一个线程时,都会使用LockSupport工具类来完成相应的工作.LockSupport定义了一组公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能 ...

  8. c#自定义业务锁

    我们有这样的使用场景,某个订单在修改信息的时候,其他人不能修改相关的信息,比如不能做支付,不能退单等等,那么我们可以根据单号进行加锁,多Monitor做了如下扩展 定义接口 //// 文件名称:ILo ...

  9. 万字长文!从底层开始带你了解并发编程,彻底帮你搞懂java锁!

    线程是否要锁住同步资源 锁住 悲观锁 不锁住 乐观锁 锁住同步资源失败 线程是否要阻塞 阻塞 不阻塞自旋锁,适应性自旋锁 多个线程竞争同步资源的流程细节有没有区别 不锁住资源,多个线程只有一个能修改资 ...

随机推荐

  1. Altium Designer 19 导出光绘文件

    一.点击 文件--制造输出--Gerber Files 第一次设置如下 绘制层点击进去全选 钻孔光圈 符号大小50mil 生成文件 关闭不用保存 蚀刻图 二.点击 文件--制造输出--Gerber F ...

  2. 在MySQL登录时出现Access denied for user 'root'@'localhost' (using password: YES) 拒绝访问,并可修改MySQL密码

    这两天装了一个mysql 5.7数据库,但是在本地dos登陆不上去,报错Access denied for user 'root'@'localhost'(using password:YES): 也 ...

  3. struts2的相关知识(实现原理、拦截器)

    struts2的实现原理 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的 ...

  4. 未能加载文件或程序集 ICSharpCode.SharpZipLib

    Ui调用Webservice ,Webservice调用Bl BL中明明有那个dll文件 后来发现是webservice里面没有 在附加调试的时候,断点在bl层中

  5. PHP实现跨服务器session共享的方法教程

    今天带来PHP实现跨服务器session共享的方法教程. 本文实例讲述了PHP实现cookie跨域session共享的方法.分享给大家供大家参考,具体如下: 做过web开发的小伙伴们都了解cookie ...

  6. ruby类对象和对象

    class Box def initialize(w,h) @width,@height=w,h end def getArea puts "class of self #{self.cla ...

  7. Cadence 学习

    记录学习Cadence的资料 Cadence 16.6软件             链接: http://pan.baidu.com/s/1mgwSeYs 密码: jemk 于博士视频教程(15.7版 ...

  8. CDN:BootCDN

    ylbtech-CDN:BootCDN BootCDN稳定.快速.免费的前端开源项目 CDN 加速服务共收录了 3351 个前端开源项目 1. 推荐返回顶部 1. bootstrap Bootstra ...

  9. java中的本地缓存

    java中的本地缓存,工作后陆续用到,一直想写,一直无从下手,最近又涉及到这方面的问题了,梳理了一下.自己构造单例.guava.ehcache基本上涵盖了目前的大多数行为了.   为什么要有本地缓存? ...

  10. Jenkins使用五:创建部署任务

    创建部署任务 选择运行节点 选择使用shell # 如果是持续进程,这里最好加一个kill进程的命令 判断如果/root/production目录存在,就删除if [ -d /root/product ...