java - volatile
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其实不是同一个,所以等于各自干各自的。