在多線程生成的緣由(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 用法的簡單舉例。