volatile主要用来使线程之间数据可见
不同线程操作同一个对象时,会先把对象复制一份给自己的运行内存然后操作完了再放回去。
如果两个线程一起操作对象,两者之间操作的对象其实不是同一个,而是各自拿到的主内存中的复制。
而volatile修饰的对象属性,会保证其可见性,使用这个属性时会同步到主内存,使其他线程知道。
volatile保证了对象属性的一致性,但是不保证原子性。有可能你这边改了一半,另一边已经又变了。。。
阿里面试题:
涉及一个容器,线程1往其中添加10个数字,线程二监控线程1,在其添加5个数字时停止。
import java.util.ArrayList;
public class Vol {
public volatile ArrayList<Integer> arr;
public Vol(){
arr = new ArrayList<Integer>();
}
public void add(int e){
arr.add(e);
}
public int size(){
return arr.size();
}
}
main
public class test {
public static void main(String[] args){
Vol v =new Vol();
Thread t1 = new Thread(){
public int stop = 0;
@Override
public void run() {
for(int i = 1; i <= 10; i++){
v.add(i);
System.out.println(i + "被加入了");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
while(true){
if(v.size() == 5){
try {
System.out.println("线程2停止");
break;
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
};
t1.start();
t2.start();
}
}
结果:
1被加入了
2被加入了
3被加入了
4被加入了
5被加入了
线程2停止
6被加入了
7被加入了
8被加入了
9被加入了
10被加入了
如果改一改,改成当线程1添加5个数字时,线程1停止
随着Thread.stop过期- -现在想从外面停一个线程最好是设置一个开关,外界控制开关,线程内部停止
public class test {
public static class Thread1 extends Thread{
public int stop = 0;
}
public static void main(String[] args){
Vol v =new Vol();
Thread1 t1 = new Thread1(){
@Override
public void run() {
int i = 0;
while(stop == 0){
i++;
v.add(i);
System.out.println(i + "被加入了");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
while(true){
if(v.size() == 5){
try {
System.out.println("线程1停止");
t1.stop = 1;
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
};
t1.start();
t2.start();
}
}
可以试试把volatile去掉- -会一直走下去,因为t1 和 t2 看到的对象v其实不是同一个,所以等于各自干各自的。