1. JUC 简介
在 Java 5.0 提供了 java.util.concurrent
(简称JUC)包,在此包中增加了在并发编程中很常用的工具类,
用于定义类似于线程的自定义子系统,包括线程池,异步 IO 和轻量级任务框架;还提供了设计用于多线程上下文中的 Collection 实现等;
2. volatile 关键字
volatile 关键字: 当多个线程进行操作共享数据时,可以保证内存中的数据是可见的;相较于 synchronized 是一种
较为轻量级的同步策略;
volatile 不具备"互斥性";
volatile 不能保证变量的"原子性";
// 使用 volatile 之前
public class TestVolatile{
public static void main(String[] args){
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("########");
break;
}
}
}
}
class ThreadDemo implements Runnable{
private boolean flag = false;
public void run(){
try{
// 该线程 sleep(200), 导致了程序无法执行成功
Thread.sleep(200);
}catch(InterruptedException e){
e.printStackTrace();
}
flag = true;
Sytem.out.println("flag="+isFlag());
}
public boolean isFlag(){
return flag;
}
public void setFlag(boolean flag){
this.flag = flag;
}
}
// 解决问题方式一: 同步锁
// 但是,效率太低
public class TestVolatile{
public static void main(String[] args){
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
// 使用同步锁
synchronized(td){
if(td.isFlag()){
System.out.println("########");
break;
}
}
}
}
}
// 解决方式二: 使用 volatile 关键字
public class TestVolatile{
public static void main(String[] args){
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("########");
break;
}
}
}
}
class ThreadDemo implements Runnable{
private volatile boolean flag = false;
同上(略)
}
3. i++ 的原子性问题
1.i++的操作实际上分为三个步骤: “读-改-写”;
2.原子性: 就是"i++"的"读-改-写"是不可分割的三个步骤;
3.原子变量: JDK1.5 以后, java.util.concurrent.atomic包下,提供了常用的原子变量;
原子变量中的值,使用 volatile 修饰,保证了内存可见性;
CAS(Compare-And-Swap) 算法保证数据的原子性;
int i = 10;
i = i++; // 此时, i=10
执行步骤:
int temp = i;
i = i + 1;
i = temp;
// 测试类
public class TestAtomicDemo{
public static void main(String[] args){
AtomicDemo ad = new AtomicDemo();
for(int i=0; i < 10; i++){
new Thread(ad).start();
}
}
}
class AtomicDemo implements Runnable{
private int serialNumber = 0;
public void run(){
try{
Thread.sleep(200);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName() + ":" + getSerialNumber());
}
public int getSerialNumber(){
return serialNumber++;
}
}
// 改进: 使用原子变量
class AtomicDemo implements Runnable{
private AtomicInteger serialNumber = new AtomicInteger();
public void run(){
try{
Thread.sleep(200);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+":"+getSerialNumber());
}
public int getSerialNumber(){
// 自增运算
return serialNumber.getAndIncrement();
}
}
3.1 CAS 算法
CAS(Compare-And-Swap) 算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问;
CAS 是一种无锁的非阻塞算法的实现;
CAS 包含了三个操作数:
需要读写的内存值: V
进行比较的预估值: A