一、什么情况下使用线程同步
很多时候,我们并不知道在什么情况下使用线程同步。在错误的情况下,就会影响性能。在正确的情况下,我们就可以防止程序出现错误。是数据的安全得到保证。
线程同步一般使用在共享数据情况下,就是说共享数据,需要使用线程同步进行保护起来,使数据的安全得到保证。比如:在电子商务中,商品的库存,是共享的数据。
二、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中。