volatile概念:
volatile关键字的主要作用是使变量在多个线程间可见。
volatile的作用:
就是强制线程到主内存(共享内存)里去读取变量,而不去线程工作内存区里去读取,从而实现了多个线程间的变量可见。也就是满足线程安全的可见性。
理解:
在java中,每一个线程都会有一块工作内存区,其中存放着所有线程共享的主内存中的变量值的拷贝。当线程执行时,他在自己的工作内存区中操作这些变量。为了存取一个共享的变量,一个线程通常先获取锁定并去清除它的内存工作区,把这些共享变量从所有线程的共享内存区中正确的装入到他自己所在的工作内存区中,当线程解锁时保证该工作内存区中变量的值写回到共享内存中。
一个线程可以执行的操作有使用(use)、赋值(assign)、装载(load)、存储(store)、锁定(lock)、解锁(unlock)。
而主内存可以执行的操作有读(read)、写(write)、锁定(lock)、解锁(unlock),每个操作都是原子的。
通俗理解:
因为线程运行,run()方法,会自动创建自己的内存区域,会把成员变量(共享数据)拷贝一份到自己的内存区域,如果外部修改这个成员变量,会导致run方法自己开辟的内存区域中中的值和成员变量值不一致,volatile的作用就是强行让run方法读取成员变量,把数据同步!
package com.bjsxt.base.sync007;
public class RunThread extends Thread{
private volatile boolean isRunning = true;
private void setRunning(boolean isRunning){
this.isRunning = isRunning;
}
public void run(){
System.out.println("进入run方法..");
int i = 0;
while(isRunning == true){
//..
}
System.out.println("线程停止");
}
public static void main(String[] args) throws InterruptedException {
/**
* 开辟主内存:
* 存储共享内存数据:isRunning
* 如果new出RunThread的很多实例对象,这些对象都可以访问这个共享内存数据
*/
RunThread rt = new RunThread();
/**
* 调用start方法,执行run方法
* 开辟rt线程工作内存区
* 把共享内存数据拷贝到自己的工作内存区
*/
rt.start();
Thread.sleep(1000);
/**
* 如果isRunning加了volatile关键字修饰
* 就会强制rt在共享内存中读取数据,这时rt又会把这个数据拷贝到自己的工作内存区
* 否则rt还是读取自己工作内存区,将不知道共享数据已经变化了
*/
rt.setRunning(false);
System.out.println("isRunning的值已经被设置了false");
/**
* volatile概念:volatile关键字的主要作用是使变量在多个线程间可见。
*/
}
}
又一例:
package com.bjsxt.base.conn008;
import java.util.ArrayList;
import java.util.List;
public class ListAdd1 {
/**
* volatile修饰符加在可能有多个线程访问的公共资源上
* 更具体点:如果有多个线程要在run方法中,用到这个资源,如果想实现这几个线程之间资源同步,就一定要加volatile,
* 或者用synchronized提供线程的安全访问也行,否则,一个线程操作了这个资源,在其他线程中将得不到体现
*/
private volatile static List<String> list = new ArrayList<String>();
public void add(){
list.add("bjsxt");
}
public int size(){
return list.size();
}
/**
* main函数
* @param args
*/
public static void main(String[] args) {
final ListAdd1 list1 = new ListAdd1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
for(int i = 0; i <10; i++){
list1.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while(true){
//如果资源list没有加volatile修饰符,第一个线程的添加元素操作,将永远得不到体现
if(list1.size() == 5){
System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");
throw new RuntimeException();
}
}
}
}, "t2");
t1.start();
t2.start();
}
}