在多线程生成的缘由(Java内存模型与i++操做解析) 中,介绍了Java的内存模型,从而可能致使的多线程问题。synchronized就是避免这个问题的解决方法之一。除了 synchronized 的方式,还有 lock,condition,volatile,threadlocal,atomicInteger,cas等方式。安全
它的修饰对象有几种:多线程
其做用的范围是synchronized后面括号括起来的部分,做用的对象是这个类的全部对象,以下代码:并发
class ClassName { public void method() { synchronized(ClassName.class) { // todo } } }
Synchronized修饰一个方法很简单,就是在方法的前面加synchronized,例如:函数
public synchronized void method() { // todo }
另外,有几点须要注意:ui
咱们知道静态方法是属于类的而不属于对象的。一样的,synchronized修饰的静态方法锁定的是这个类的全部对象。以下:this
public synchronized static void method() { // todo }
对于 synchronized ,我的以为是一种比较粗糙的加锁,尤为是对整个对象,或者整个类进行加锁的时候。例如,HashTable,它至关于 HashMap的线程安全版本。实现以下:atom
public synchronized V get(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return (V)e.value; } } return null; }
能够看到,不少方法都是使用了 synchronized 进行了修饰,那么就意味若是还有别的同步方法x,这个x方法和get方法即便在没有冲突的状况下也须要等待执行。这样效率上 必然会有必定的影响,因此会有 ConcurrentHashMap 进行分段加锁。线程
另外,在JDK中,Collections有一个方法能够把不是线程安全的集合转化为线性安全的集合,它是这样实现的:code
public static <T> Collection<T> synchronizedCollection(Collection<T> c) { return new SynchronizedCollection<>(c); } static class SynchronizedCollection<E> implements Collection<E>, Serializable { private static final long serialVersionUID = 3053995032091335093L; final Collection<E> c; // Backing Collection final Object mutex; // Object on which to synchronize SynchronizedCollection(Collection<E> c) { this.c = Objects.requireNonNull(c); mutex = this; } SynchronizedCollection(Collection<E> c, Object mutex) { this.c = Objects.requireNonNull(c); this.mutex = Objects.requireNonNull(mutex); } public int size() { synchronized (mutex) {return c.size();} } ......
能够看到 在构造函数中 有 mutex = this, 而后在具体的方法使用了 synchronized(mutex),这样就会对调用该方法的对象进行加锁。仍是会出现HashTable 出现的那种问题,也就是效率不高。对象
以上就是 JDK 对于 synchronized 用法的简单举例。