线程同步详细讲解

社会主义新天地 提交于 2020-04-07 07:35:38

一、什么情况下使用线程同步

           很多时候,我们并不知道在什么情况下使用线程同步。在错误的情况下,就会影响性能。在正确的情况下,我们就可以防止程序出现错误。是数据的安全得到保证。

            线程同步一般使用在共享数据情况下,就是说共享数据,需要使用线程同步进行保护起来,使数据的安全得到保证。比如:在电子商务中,商品的库存,是共享的数据。

二、Volatile变量

            相对于synchronized来说,volatile是比较轻量级的线程同步锁。synchronized一般使用在函数上。比如:

public synchronized int get() {return value;}

而Volatile变量,用来确保将变量的更新操作通知到其它线程。当把变量声明为Volatile类型后,编译器与运行时都会注意到这个变量是共享的。

            Volatile变量通常用做某个操作完成、发生中断或者状态的标志。Volatile的语义不足以确保递增操作(count++)的原子性,除非你能确保只有一个线程对变量执行写操作。比如:

volatile boolean asleep;

while(!asleep)
   conutSome();

三、线程封闭

            当访问共享的可变数据时,通常需要使用同步。一种避免使用同步的方式就是不共享数据。如果仅在单线程内访问数据,就不需要同步。这种技术被称为线程封闭。线程封闭技术有两种:一栈封闭;二是ThreadLocal类。这篇文章只讲讲第二种的应用,因为是我们经常使用的。

            ThreadLocal对象通常用于防止对可变的单实例变量或全局变量进行共享。比如,在单线程应用程序中可能会维持一个全局的数据库连接。所以,一般使用在JDBC中,通过将JDBC的链接保存到ThreadLocal对象中,每个线程都会拥有属于自己的链接。     

public class DBContextHolder {
		
		private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
		  
		public static void setDBType(String dbType) {  
		    contextHolder.set(dbType);  
		}  
		  
		public static String getDBType() {  
		    return contextHolder.get();  
		}  
		  
		public static void clearDBType() {  
		    contextHolder.remove();  
		}  
}

调用:

public class DynamicDataSource extends AbstractRoutingDataSource {

	// 查找当前用户上下文变量中设置的数据源
	protected Object determineCurrentLookupKey() {
		return DBContextHolder.getDBType();//这里调用
	}

	// 设置默认的数据源
	public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
		super.setDefaultTargetDataSource(defaultTargetDataSource);
	}

	// 设置数据源集合.
	public void setTargetDataSources(Map targetDataSources) {
		super.setTargetDataSources(targetDataSources);
	}
}

            当某个频繁执行的操作需要一个临时对象,例如一个缓冲区,而同时又希望避免在每次执行时都重新分配该临时对象,就可以使用这项技术。

四、不变性

            在线程同步中,有三种性质:可见性、原子性、不变性。前面的synchronized可以确保原子性,而Volatile可以确保可见性。那么不变性,就用Final域来进行讲解。不变性主要使对象具有不可变,进而得出:不可变对象一定是线程安全的。但不可变性并不等于将对象中所有的域都声明为final类型,即使对象中所有的域都为final类型的,这个对象也仍然是可变的,因为在final类型的域中可以保存对可变对象的应用。

            当满足以下条件时,对象才是不可变的:

            1.对象创建以后其状态就不能修改。2.对象的所有域都是final类型。3.对象是正确创建的。

五、Java中有哪些类是线程同步的

            很多时候,我们是直接调用Java Jdk原有的类,进行对数据的包装,进而使数据达到线程同步。以下线程安全库中的容器类提供了一下的安全发布保证:

            1.通过将一个键或者值放入Hashtable、synchronizedMap或者ConcurrentMap中,可以安全地将它发布给如何从这些容器中访问它的线程。

            2.通过将某个元素放入Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、synchronizedList或synchronizedSet中。

            3.通过将某个元素放入BlockingQuete或者ConcurrentLinkedQueue中。

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!