文档章节

JAVA CAS技术运用于多线程(Unsafe)

P&H
 P&H
发布于 2013/10/04 20:43
字数 817
阅读 2977
收藏 14

在此输入图片描述

我们来测试如下代码,注意代码的写法:

1、普通的写法:

if (unsafe_var == 23) {

// System.out.println("我判断出来了,unsafe_var ==23,我设置为46..");

// try {

// //模拟业务代码

// Thread.sleep(1000);

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

// unsafe_var = 46;

// }

可以看到打印出多行:

我判断出来了,unsafe_var ==23,我设置为46..

我判断出来了,unsafe_var ==23,我设置为46..

2、用Unsafe提供的CAS技术,可以这样写:

if (unsafe.compareAndSwapInt(this, intParamOffset, 23, 46)) {

			try {

				////模拟业务代码

				Thread.sleep(1000);

			} catch (InterruptedException e) {

				e.printStackTrace();

			}

			System.out.println("我判断出来了,unsafe_var == 23,我设置为46..");

		}

由于原子性,多个线程只会打印一行:

我判断出来了,unsafe_var == 23,我设置为46.

测试代码如下:

package com.xue.gang.volatiler.unsafe;

import java.lang.reflect.Field;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import sun.misc.Unsafe;

public class UnsafeRunner {

public static void main(String args[]) throws InterruptedException {

	int size = 1000;

	CountDownLatch countDownLatch = new CountDownLatch(size);

	TomUnsafeRunner tomRunner = new TomUnsafeRunner(false, countDownLatch,
			"runner");

	ExecutorService executorService = Executors.newCachedThreadPool();

	for (int i = 1; i <= size; i++) {
		executorService.execute(new Thread2RunUnsafe(countDownLatch,
				tomRunner, i + "_号"));
	}
	countDownLatch.await();
	executorService.shutdown();

	// new Thread(volatileRunner).start();
}

static class Thread2RunUnsafe implements Runnable {
	private CountDownLatch countDownLatch;
	private TomUnsafeRunner tomRunner;
	private String name;

	public Thread2RunUnsafe(CountDownLatch countDownLatch,
			TomUnsafeRunner tomRunner, String name) {
		super();
		this.countDownLatch = countDownLatch;
		this.tomRunner = tomRunner;
		this.name = name;
	}

	public void run() {
		System.out.println(this.name + ":running...");
		this.tomRunner.doWork();
		System.out.println(this.name + ":结束...");
		this.countDownLatch.countDown();

	}
}

static class TomUnsafeRunner {

	volatile boolean shutdownRequested = false;
	// boolean shutdownRequested = false;
	String name;
	int unsafe_var = 23;

	public TomUnsafeRunner(boolean shutdownRequested,
			CountDownLatch countDownLatch, String name) {
		super();
		this.shutdownRequested = shutdownRequested;

		this.name = name;
	}

	public void shutdown() {
		this.shutdownRequested = true;
	}

	public void doWork() {


		////////////////////一般写法///////////////

// if (unsafe_var == 23) {

// System.out.println("我判断出来了,unsafe_var ==23,我设置为46..");

// try {

// //模拟业务代码

// Thread.sleep(1000);

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

// unsafe_var = 46;

// }

		/////////////////用JAVA CAS技术
		Unsafe unsafe = UnsafeSupport.getInstance();
		Class clazz = TomUnsafeRunner.class;
		Field[] fields = clazz.getDeclaredFields();
		System.out.println("fieldName:fieldOffset");
		// 获取属性偏移量,可以通过这个偏移量给属性设置
		for (Field f : fields) {
			System.out.println(f.getName() + ":"
					+ unsafe.objectFieldOffset(f));
		}
		// arg0, arg1, arg2, arg3 分别是目标对象实例,目标对象属性偏移量,当前预期值,要设的值
		// unsafe.compareAndSwapInt(arg0, arg1, arg2, arg3)
		// 偏移量编译后一般不会变的,intParam这个属性的偏移量
		// unsafe_var:8
		long intParamOffset = 8;

		if (unsafe.compareAndSwapInt(this, intParamOffset, 23, 46)) {
			try {
				////模拟业务代码
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("我判断出来了,unsafe_var == 23,我设置为46..");
		}
	}
}
static class UnsafeSupport {
	//private static Logger log = Logger.getLogger(UnsafeSupport.class);

	private static Unsafe unsafe;

	static {
		Field field;
		try {
			// 由反编译Unsafe类获得的信息
			field = Unsafe.class.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			// 获取静态属性,Unsafe在启动JVM时随rt.jar装载
			unsafe = (Unsafe) field.get(null);
		} catch (Exception e) {
			//log.error("Get Unsafe instance occur error", e);
		}
	}

	/**
	 * 获取{@link Unsafe }
	 */
	public static Unsafe getInstance() {
		return unsafe;
	}
}

}

运行以上代码,设置Eclipse:

将Windows->Preferences->Java-Complicer->Errors/Warnings->Deprecated and restricted API,中的Forbidden references(access rules)设置为Warning,即可以编译通过。

参考blog:

http://zeige.iteye.com/blog/1182571

http://blog.csdn.net/hengyunabc/article/details/7657934 (作者有个测试,unsafe写入1百万条log用时0.234秒,用java自带的logger,用时7.347秒)

© 著作权归作者所有

P&H

P&H

粉丝 22
博文 106
码字总数 37336
作品 0
成都
技术主管
私信 提问
Java Concurrency(二)——J.U.C atomic包源码解读

java5之后的java.util.concurrent包是世界级并发大师Doug Lea的作品,里面主要实现了 atomic包里Integer/Long对应的原子类,主要基于CAS; 一些同步子,包括Lock,CountDownLatch,Semaphore...

谦谦君子
2015/01/06
1K
2
无锁的同步策略——CAS操作详解

1. 从乐观锁和悲观锁谈起 乐观锁和悲观锁是两种不同的解决并发问题的策略。悲观锁策略假定任何一次并发都会发生冲突,所以总是采用最严格的方式来进行并发控制。java中的独占锁(synchronized...

takumiCX
2018/07/14
0
0
Java 并发编程源码解析汇总篇

java并发编程,内存模型 java并发编程,volatile内存实现和原理 Java并发编程,并发基础 Java 并发编程,线程池(ThreadPoolExecutor)源码解析 Java并发编程,Executor 框架介绍 Java并发编...

郑加威
2018/12/23
0
0
111 多线程JUC包下代码分析

Java多线程系列目录(共43篇) AtomicLongFieldUpdater:通过反射+CAS实现对传入对象的指定long字段实现类似AtomicLong的操作 http://www.cnblogs.com/skywang12345/p/javathreadscategory.ht...

素雷
2017/10/31
42
0
Java魔法类——Unsafe应用解析

前言 Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源...

微笑向暖wx
02/19
22
0

没有更多内容

加载失败,请刷新页面

加载更多

1、Docker学习,第一天

Docker学习,第一天 一、Docker简介 环境配置如此之麻烦,换台机器,重来一次,费事费力。安装的时候,把原始环境一模一样的复制过来。开发人员利用Docker可以消除写作编码时,”在我的机器上...

有一个小阿飞
18分钟前
3
0
10.23

一、编写一个程序,把用分钟表示的时间转换成用小时和分钟表示的时间。使用#define或const创建一个表示60的符号常量或const变量。通过while循环让用户重复输入值,直到用户输入小于或等于0...

197王彧涛
44分钟前
3
0
手机视频如何制作GIF动图

很多小伙伴都喜欢用GIF动图在各大社交软件上与好友斗图,那你知道这些好玩有趣的GIF动图是如何制作的吗?下面教你一个将手机视频制作成GIF动图的方法,让你都可以随时随地制作有趣的表情包,...

白米稀饭2019
49分钟前
5
0
Spring Security 实战干货:实现自定义退出登录

1. 前言 上一篇对 Spring Security 所有内置的 Filter 进行了介绍。今天我们来实战如何安全退出应用程序。 2. 我们使用 Spring Security 登录后都做了什么 这个问题我们必须搞清楚!一般登录...

码农小胖哥
今天
11
0
JVM核心知识-类加载机制

JVM中类的生命周期包括7个阶段,加载、准备、验证、解析、初始化、使用、卸载。其中准备、验证、解析被归为连接阶段。 加载 jvm在这个阶段完成的工作 通过类名获取类的二进制字节流 将这个字...

moon888
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部