Java多线程再学习,温故知新(三)volatile

线程变量的可见性:

一个线程修改了这个变量的值,在另外一个线程中能够读到这个修改后的值。


Synchronized除了线程之间互斥意外,还有一个非常大的作用,就是保证可见性,比如以下例子中get和set方法被synchronized关键字修饰,他们两个同时的可见变量是a;synchronized可以保证同一个实例,在多线程的环境下get和set方法操控的变量能保持一致。

/**
 * 保证可见性的前提
 * 多个线程拿到的是同一把锁,否则是保证不了的。
 * 
 */
public class Demo {

	private int a = 1;

	public synchronized int getA() {
		return a;
	}

	public synchronized void setA(int a) {
		try {
			Thread.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.a = a;
	}

	public static void main(String[] args) {
		Demo demo = new Demo();
		new Thread(new Runnable() {
			@Override
			public void run() {
				demo.setA(10);
			}
		}).start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(demo.getA());
			}
		}).start();

		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("最终的结果为:" + demo.getA());
	}
}

Volatile称之为轻量级锁,被volatile修饰的变量,在线程之间是可见的。如下例子第一个线程执行完毕后第二个线程执行。一个线程修改变量后,另一个线程马上可见。

public class Demo2 {
	public volatile boolean run = false;
	
	public static void main(String[] args) {
		
		Demo2 d = new Demo2();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for(int i = 1;i<=10;i++) {
					System.err.println("执行了第 " + i + " 次");
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				d.run = true;
			}
		}).start();
		
		new Thread(new Runnable() {
			//第一个线程执行完毕后,第二个线程执行
			@Override
			public void run() {
				while(!d.run) {
					// 不执行
				}
				System.err.println("线程2执行了...");
			}
		}).start();
	}
}

Volatile的字节码指令相当于Lock指令


    将当前处理器缓存行的内容写回到系统内存。
    写回到内存的操作会使在其他CPU里缓存了该内存地址的数据失效 ,保证多线程下变量数据的一致性。
    无法解决多线程环境下,对变量的原子性操作如自增
 

JDK提供的原子类原理及使用

java.util.concurrent.atomic
原子更新基本类型

import java.util.concurrent.atomic.AtomicInteger;

public class Sequence {

	private AtomicInteger value = new AtomicInteger(0);

	public int getNext() {
		return value.getAndIncrement();
	}

	public static void main(String[] args) {

		Sequence s = new Sequence();

		new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {
					System.out.println(Thread.currentThread().getName() + " " + s.getNext());
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();

		new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {
					System.out.println(Thread.currentThread().getName() + " " + s.getNext());
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();

		new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {
					System.out.println(Thread.currentThread().getName() + " " + s.getNext());
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();

	}
}

原子更新数组

	private int [] s = {2,1,4,6};
	
	AtomicIntegerArray a = new AtomicIntegerArray(s);

原子更新抽象类型

//主要操作get和set方法
AtomicReference<User> user = new AtomicReference<>();

原子更新字段 

//需要操作哪个字段,字段必须要经过volatile修饰
AtomicIntegerFieldUpdater<User> old =  AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
	
User user = new User();
//进行自增操作
System.out.println(old.getAndIncrement(user));

猜你喜欢

转载自blog.csdn.net/ieflex/article/details/86478397
今日推荐