synchronized是Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块。
synchronized一般有两种用法:synchronized方法和synchronized代码块。
1.synchronized方法:
public class SynchronizedDemo { private static int count = 0; public synchronized void syncMethod() { System.out.println(Thread.currentThread().getName()); for (int i = 0; i < 3; i++) { count++; System.out.println(count); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { SynchronizedDemo demo = new SynchronizedDemo(); for (int i = 0; i < 3; i++) { Thread thread = new Thread() { @Override public void run() { demo.syncMethod(); } }; thread.start(); } } }执行结果如下:
Thread-0
1
2
3
Thread-1
4
5
6
Thread-2
7
8
9
main方法中创建了3个线程,3个线程都调用了SynchronizedDemo类的同一实例的synchronized方法,一个线程调用时,其他线程被阻塞,从而实现了线程同步。
如果在main方法中为每个线程创建一个SynchronizedDemo类的实例,结果会是什么呢?
public static void main(String[] args) { for (int i = 0; i < 3; i++) { SynchronizedDemo demo = new SynchronizedDemo(); Thread thread = new Thread() { @Override public void run() { demo.syncMethod(); } }; thread.start(); } }执行结果如下:
Thread-1
Thread-2
1
Thread-0
2
3
4
5
6
7
8
9
由于为每个线程都创建了SynchronizedDemo类的实例,由于synchronized方法是每个类实例对应一把锁,所以各个线程互不干扰,不会同步执行。
需要注意的是:如果将一个大的方法声明为synchronized,将会大大影响效率,所以尽量避免使用synchronized方法。
2.synchronized代码块:
1) synchronized(this)
public class SynchronizedDemo { private static int count = 0; public void syncTest() { synchronized (this) { System.out.println(Thread.currentThread().getName()); for (int i = 0; i < 3; i++) { count++; System.out.println(count); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { SynchronizedDemo demo = new SynchronizedDemo(); for (int i = 0; i < 3; i++) { Thread thread = new Thread() { @Override public void run() { demo.syncTest(); } }; thread.start(); } } }执行结果如下:
Thread-0
1
2
3
Thread-1
4
5
6
Thread-2
7
8
9
synchronized(this),被锁住的是当前对象,也就是SynchronizedDemo类的实例,在main方法中,我们操作的是一个SynchronizedDemo类的实例,所以当一个线程得到当前锁的时候,其他线程就被阻塞了,直到当前线程执行完毕将锁释放。如果我们在main方法中为每个线程new一个SynchronizedDemo类的实例,结果会怎样呢?有兴趣的读者可以自己改一下代码然后运行看看结果。
2) synchronized(class)
public class SynchronizedDemo { private static int count = 0; public void syncTest() { synchronized (SynchronizedDemo.class) { System.out.println(Thread.currentThread().getName()); for (int i = 0; i < 3; i++) { count++; System.out.println(count); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { for (int i = 0; i < 3; i++) { SynchronizedDemo demo = new SynchronizedDemo(); Thread thread = new Thread() { @Override public void run() { demo.syncTest(); } }; thread.start(); } } }执行结果如下:
Thread-0
1
2
3
Thread-1
4
5
6
Thread-2
7
8
9
synchronized(SynchronizedDemo.class),锁是当前类,所以在main方法中为每个线程都new了一个SynchronizedDemo类的实例,但是线程间依然是同步执行的。
3) synchronized(静态变量)
public class SynchronizedDemo { private static int count = 0; private final static byte[] mutex = new byte[0]; public void syncTest() { synchronized (mutex) { System.out.println(Thread.currentThread().getName()); for (int i = 0; i < 3; i++) { count++; System.out.println(count); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { for (int i = 0; i < 3; i++) { SynchronizedDemo demo = new SynchronizedDemo(); Thread thread = new Thread() { @Override public void run() { demo.syncTest(); } }; thread.start(); } } }执行结果如下:
Thread-0
1
2
3
Thread-2
4
5
6
Thread-1
7
8
9
synchronized(静态变量)和synchronized(class)类似,静态变量是在class的所有实例间共享的,所以在main方法中为每个线程都new了一个SynchronizedDemo类的实例,但是线程间依然是同步执行的。