Tips:由于 Java 中的线程是与操作系统的原生线程一一对应的,所以当阻塞一个线程时,需要从用户态切换到内核态执行阻塞操作,这是很耗时的操作,而 synchronized 的使用就会导致上下文切换。
Java 中每一个对象都可以作为锁,这是 synchronized 实现同步的基础。synchronized 的三种使用方式如下:
场景设计:
package jvm.juc;public class SynchroizedTest extends Thread{static int count = 0;public synchronized void increaseCount() {String thread = Thread.currentThread().getName();System.out.println("当前" + thread + "线程正在操作");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}count += 1;System.out.println("当前" + thread + ":" + count);}@Overridepublic void run() {increaseCount();}public static void main(String[] args) {SynchroizedTest test = new SynchroizedTest();Thread t1 = new Thread(test);Thread t2 = new Thread(test);t1.setName("threadOne");t2.setName("threadTwo");t1.start();t2.start();}}
上述程序运行结果如下图所示

Tips:仔细看 DemoTest test = new DemoTest () 这就话,我们创建了一个 DemoTest 的实例对象,对于修饰普通方法,synchronized 关键字的锁即为 test 这个实例对象。
暂时其他代码不变,然后main函数里面代码改成如下形式
public static void main(String[] args) {SynchroizedTest test = new SynchroizedTest();SynchroizedTest test2 = new SynchroizedTest();Thread t1 = new Thread(test);Thread t2 = new Thread(test2);t1.setName("threadOne");t2.setName("threadTwo");t1.start();t2.start();}
代码执行的结果如下图所示

可以看出,两个线程同时进入到锁中
两个线程持有两个不同的锁,不会产生互相 block。相信讲到这里,同学对实例对象锁的作用也了解了,那么我们再次将 increase 方法进行修改,将其修改成静态方法,然后输出结果。
结果如下,又得到了顺序执行

结果分析:我们看到,结果又恢复了正常,为什么会这样?
关键的原因在于,synchronized 修饰静态方法,锁为当前 class,即 DemoTest.class。
Tips:对于 synchronized 作用于同步代码,锁为任何我们创建的对象,只要是个对象即可,如 new Object () 可以作为锁,new String () 也可作为锁,当然如果传入 this,那么此时代表当前对象。
/*** synchronized 修饰实例方法*/static final Object objectLock = new Object(); //创建一个对象锁public static void increase() throws InterruptedException {System.out.println(Thread.currentThread().getName() + "获取到锁,其他线程在我执行完毕之前,不可进入。" );synchronized (objectLock) {sleep(1000);count++;System.out.println(Thread.currentThread().getName() + ": " + count);}}
代码解析:我们创建了一个 objectLock 作为对象锁,除了第一句打印语句,让后三句代码加入了 synchronized 同步代码块,当 threadOne 进入时,threadTwo 不可进入后三句代码的执行。

上一篇:Java字符串(String类)