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);
- }
-
- @Override
- public 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 不可进入后三句代码的执行。