Java并发(4)--线程安全:原子性(Atomic)、可见性、有序性

线程安全定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程如何交替运行,并且在主调程序中不需要额外的同步或者协同,这个类都能表示出正确的行为,那么就称这个类为线程安全的。

线程安全主要体现在三个方面,分别是原子性、可见性、有序性。
==1==

一. 原子性

1: Atomic包

Java并发编程-无锁CAS与Unsafe类及其并发包Atomic
在Atomic包共提供了13个原子操作类,这些写原子操作类提供了一些简单高效的更新变量的方式。Atomic包里的类都是基于Unsafe类实现的包装类。这13个类主要分为

原子更新基本类型、原子更新数组、原子更新引用、原子更新属性

1. AtomicInteger原子类:基本类型

AtomicInteger 属于原子更新基本类型
AtomicInteger测试类:


package com.hust.concurrency.service.atomic;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;

import com.hust.concurrency.annoations.ThreadSafe;

import lombok.extern.slf4j.Slf4j;

/**
* @Description  原子操作类
* @since  2019年1月8日 下午8:37:54
* @author LiuLiBin
*/
@Slf4j
@ThreadSafe
public class AtomicIntegerTest {
	
	//请求总数
	public static int clientTotal = 1000;
	
	//同时并发执行的线程数
	public static int threadTotal = 50;
	
	//测试并发 的计数值
	public static AtomicInteger count = new AtomicInteger(0) ;
	
	public static void main(String[] args) throws InterruptedException {
		
		//定义线程池
		ExecutorService executorService = Executors.newCachedThreadPool();
		
		//定义信号量 ,信号量为 50
		final Semaphore semaphore = new Semaphore(threadTotal);
		
		//定义计数器闭锁 ,期望所有请求请求完后统计计数结果 
		final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
		
		//放入请求,将请求线程全部放入线程池中
		for (int i = 0; i < clientTotal; i++) {

			executorService.execute(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					try {
						semaphore.acquire(); // 获取一个许可
						add();
						semaphore.release(); // 释放一个许可
					} catch (Exception e) {

						log.error("exception", e);
					}
					countDownLatch.countDown(); // 计数器闭锁减1
				}
			});
		}
		
		//在所有线程请求执行完后 ,唤醒等待线程 ,此处涉及到countDownLatch 的实现机制
		countDownLatch.await();
		
		//关闭线程池
		executorService.shutdown();
		
		//打印计数值信息
		log.info("count:{}",count.get());
		
		
		
	}
	
	/**
	 * 增加计数值
	 */
	private static void add() {
		//以原子的方式将当前值加1,并返回加1后的值
		count.incrementAndGet();
	}
}

在上面代码中,count.incrementAndGet()方法是基于 compareAndSet 方法实现以原子的方式将当前值加1,并返回加1后的值。下面来看下AtomicInteger 的部分源码:
==2==
在上图中,compareAndSwapInt() 方法就是java 程序中的CAS指令,虚拟机在内部对这个方法进行了特殊处理,即时编译出来的是一条与平台相关的处理器CAS指令。
==3==

2. 原子更新数组、原子更新引用、原子更新属性

详见链接:原子操作类

3. AtomicStampReferenc:CAS的ABA问题

==4==

2: synchronized关键字

详见:深入理解Java并发之synchronized实现原理

二. 可见性

可见性是指当一个线程修改了共享变量的值,其他线程能够立即得到这个修改。volatile、synchronized 、final 修饰的变量都可以实现可见性
==5==
==6==

三.有序性

有序性是指对于单线程的执行代码,我们总是认为代码的执行是按顺序依次执行的,这样的理解并没有毛病,毕竟对于单线程而言确实如此,但对于多线程环境,则可能出现乱序现象,因为程序编译成机器码指令后可能会出现指令重排现象,重排后的指令与原指令的顺序未必一致,要明白的是,在Java程序中,倘若在本线程内,所有操作都视为有序行为,如果是多线程环境下,一个线程中观察另外一个线程,所有操作都是无序的,前半句指的是单线程内保证串行语义执行的一致性,后半句则指指令重排现象和工作内存与主内存同步延迟现象。


参考:
深入理解Java并发之synchronized实现原理
Java并发编程-无锁CAS与Unsafe类及其并发包Atomic

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值