不少时候,咱们并不知道在什么状况下使用线程同步。在错误的状况下,就会影响性能。在正确的状况下,咱们就能够防止程序出现错误。是数据的安全获得保证。java
线程同步通常使用在共享数据状况下,就是说共享数据,须要使用线程同步进行保护起来,使数据的安全获得保证。好比:在电子商务中,商品的库存,是共享的数据。数据库
相对于synchronized来讲,volatile是比较轻量级的线程同步锁。synchronized通常使用在函数上。好比:安全
public synchronized int get() {return value;}
而Volatile变量,用来确保将变量的更新操做通知到其它线程。当把变量声明为Volatile类型后,编译器与运行时都会注意到这个变量是共享的。函数
Volatile变量一般用作某个操做完成、发生中断或者状态的标志。Volatile的语义不足以确保递增操做(count++)的原子性,除非你能确保只有一个线程对变量执行写操做。好比:性能
volatile boolean asleep; while(!asleep) conutSome();
当访问共享的可变数据时,一般须要使用同步。一种避免使用同步的方式就是不共享数据。若是仅在单线程内访问数据,就不须要同步。这种技术被称为线程封闭。线程封闭技术有两种:一栈封闭;二是ThreadLocal类。这篇文章只讲讲第二种的应用,由于是咱们常用的。spa
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(); } }
调用:code
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类型的域中能够保存对可变对象的应用。rem
当知足如下条件时,对象才是不可变的:
1.对象建立之后其状态就不能修改。2.对象的全部域都是final类型。3.对象是正确建立的。
不少时候,咱们是直接调用Java Jdk原有的类,进行对数据的包装,进而使数据达到线程同步。如下线程安全库中的容器类提供了一下的安全发布保证:
1.经过将一个键或者值放入Hashtable、synchronizedMap或者ConcurrentMap中,能够安全地将它发布给如何从这些容器中访问它的线程。
2.经过将某个元素放入Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、synchronizedList或synchronizedSet中。
3.经过将某个元素放入BlockingQuete或者ConcurrentLinkedQueue中。