java多线程之volatile

184 阅读2分钟

layout: post title: "java多线程之wait/notify机制" subtitle: " "1.wait引起当前执行线程等待 2.notify唤醒线程 "" date: 2018-10-07 08:00:00 author: "青乡" header-img: "img/post-bg-2015.jpg" catalog: true tags: - multi thread

同步的几种解决方法

synchronized

并发包

volatile

没有对象锁。

同步关键字。但又不能真正的同步,也就是说不能排他锁。多个线程可以同时读写。

那有什么作用呢?可以确保线程可见性,一个线程在修改数据,另一个线程始终可以读到最新被修改的值,而不是旧值。

volatile 数据;

线程1 修改数据;

线程2 读数据; //读到的始终是最新被线程1修改的值。而如果使用对象锁,可能读到的是旧的值,因为线程1执行过程当中或者修改数据期间,线程2读的数据是旧的。

很少使用

1.工作使用很少
2.jdk使用很少
3.应用场景很少

工作使用

package com.gzh.dpp.csp.instruction;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.gzh.commons.context.AppContext;
import com.gzh.commons.http.HttpClientUtils;

public class MainCSPI {
	
	private static Log log = LogFactory.getLog(MainCSPI.class);
	private static volatile boolean running = true; //作为程序开关
	
	public static void main(String[] args) {
		
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				
				try {					
					
					HttpClientUtils.getInstance().shutdown();
					
					AppContext.stop();
					
					log.info(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " Main server stopped!");
				}catch (Throwable t) {
                    log.error("Main stop error", t);
                }
				
				synchronized (MainCSPI.class) {
	                running = false;
	                MainCSPI.class.notify();
	            }
			}
		});
		try {
			AppContext.start();
			//初始化HttpClient连接
			HttpClientUtils httpClient = HttpClientUtils.getInstance();
			httpClient.setConnectionTimeout(8*1000);
			httpClient.setReadTimeout(15*1000);
		} catch (RuntimeException e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		log.info(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " Main server started!");
		
		synchronized (MainCSPI.class) {
			while (running) { //让程序一直处于运行的主状态
	            try {
	            	MainCSPI.class.wait();
	            } catch (Throwable e) {
	            }
	        }
		}
		
	}

}

jdk使用

并发包。

应用场景

作为程序开关(启动/关闭)的布尔值

满足以下2个条件,可以使用

volatile看起来简单,但是要想理解它还是比较难的,这里只是对其进行基本的了解。volatile相对于synchronized稍微轻量些,在某些场合它可以替代synchronized,但是又不能完全取代synchronized,只有在某些场合才能够使用volatile。

使用它必须满足如下两个条件:
1.对变量的写操作不依赖当前值;
2.该变量没有包含在具有其他变量的不变式中。

volatile经常用于两个两个场景:状态标记两、double check

面试题

  1. Java中的Volatile关键是什么作用?怎样使用它?在Java中它跟synchronized方法有什么不同?

自从Java 5和Java内存模型改变以后,基于volatile关键字的线程问题越来越流行。应该准备好回答关于volatile变量怎样在并发环境中确保可见性、顺序性和一致性。


总结
1.优点
确保读线程始终可以读到写线程的最新值。即确保所谓的线程可见性,线程执行顺序。

2.缺点
没有锁,不能同步。即不能确保所谓的数据一致性。

是否允许final

不允许。

volatile adj 挥发的,不稳定的 //所以不是常量

参考

cmsblogs.com/?p=2092

www.ibm.com/developerwo…

docs.oracle.com/javase/spec…