四、线程同步-volatile关键字

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  1. 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

  2. 禁止进行指令重排序。

写volatile变量操作与该操作之前的读、写操作都不会被重排序。

读volatile变量操作与改操作之后的读、写操作都不会被重排序

例子

	private  boolean stop=true;
	@Test
	public void test() throws Exception{
		
		Runnable run1 = new Runnable(){

			public void run() {
				// TODO Auto-generated method stub
				while(stop){
					//处理业务
					
				}
				System.out.println("2......end");
			}
			
		};
	   	Thread thread=new Thread(run1);
	   	thread.start();
		Thread.sleep(1000);
		stop=false;
		System.out.println("1......end");
		
		//等待程序运行
		thread.join();
	}

这段Demo,给线程run1设置了一个结束标志stop,主线程等待一秒后会将介素标志stop设置为false,理论上线程run1就因为stop=false而run方法结束。但是以上代码运行并没有结束。说明stop的修改对线程run1是不可见的。

实际上是因为stop字段没有用volatile修饰,JIT编译器并不知道它是多线程共享的变量。所以为了提高代码效率,会对代码进行优化成等同以下结果:

run方法优化

    while(true){
        //处理业务
    }

所以run1线程一直循环。如果用volatile修饰stop变量即可,解决。

使用场景

  1. 作为状态变量。如上面Demo,用于线程结束的标志。可以通知线程结束。
  2. 某些场景代替锁。如多个线程共享一组可变变量,要保证这些变量更新的原子性。可以将这些变量封装成对象,用volatile修饰。对这些变量更新操作可以是创建一个对象并赋予引用,volatile保证了可见性和有序性。

猜你喜欢

转载自blog.csdn.net/qq_26680031/article/details/81533460