关键字synchromized 的作用是实现线程间的同步。它的工作室对同步的代码加锁,使得每一,只有一个线程可以进入同步块,从而保证线程间的安全性。
synchromized 的用户这里做一个简单的整理,
1,指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
2,直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
3,直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。
如下面一段代码给制定对象加锁:
public class Test implements Runnable { static Object lock = new Object(); static int i = 0; @Override public void run() { for (int j = 0; j < 100000; j++) { synchronized (lock) { i++; } } } public static void main(String args[]) throws InterruptedException { Test test = new Test(); Thread thread1 = new Thread(test); Thread thread2 = new Thread(test); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println(i); } }
当然上面代码也可将synchromized关键字作用于实例方法上:
public class Test implements Runnable { static int i = 0; public synchronized void increase(){ i++; } @Override public void run() { for (int j = 0; j < 100000; j++) { increase(); } } public static void main(String args[]) throws InterruptedException { Test test = new Test(); Thread thread1 = new Thread(test); Thread thread2 = new Thread(test); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println(i); } }
同时这里一定要注意的是Thread的创建方式,这里Test类只new一个实例 ,因为synchronized 直接作用于实例方法,需要线程指向同一个实例,才能保证多线程使用的是同一个锁。
如果使用了下面的方式,那么就会产生两个Test实例,thread1和thread2也就获得了不同的锁,所以synchronized 作用于实例方法时,需要保证创建线程是同一个Runnable接口实例。
Thread thread1 = new Thread(new Test()); Thread thread2 = new Thread(new Test());
当然,使用synchronized 第三种方式将其作用于静态方法,就没有问题了
public static synchronized void increase(){ i++; }
其他,synchronized的使用个人觉得对对象加锁的方式是优于对实例方法的使用,
当某个线程进入同步方法获得对象锁,那么其他线程访问这里对象的同步方法时,必须等待或者阻塞,这对高并发的系统是致命的,这很容易导致系统的崩溃。如果某个线程在同步方法里面发生了死循环,那么它就永远不会释放这个对象锁,那么其他线程就要永远的等待。
下面是jdk对hash的实现方式,可以看到,很多方法都是使用了 synchronized 进行了修饰,那么就意味如果还有别的同步方法x,这个x方法和get方法即使在没有冲突的情况下也需要等待执行(比如有3个线程同时做读操作,实际上是不需要阻塞,可以同时进行的)。这样效率上 必然会有一定的影响,所以会有 ConcurrentHashMap 进行分段加锁
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; } public synchronized V put(K key, V value); public synchronized V remove(Object key)