上篇介绍了用synchronized修饰static方式来实现“Class 锁”,今天要介绍另一种实现方式,synchronized(class)代码块,写法不一样但是作用是一样的。下面我附上一段代码来看一下synchronized(class)代码块的基本用法,如下:
public static void main(String[] args) { Service4 s1 = new Service4(); Service4 s2 = new Service4(); ThreadA a = new ThreadA(s1); ThreadB b = new ThreadB(s2); a.setName("A"); b.setName("B"); a.start(); b.start(); } public static class ThreadA extends Thread { private Service4 service; public ThreadA(Service4 service) { super(); this.service = service; } @Override public void run() { super.run(); service.printA(); } } public static class ThreadB extends Thread { private Service4 service; public ThreadB(Service4 service) { super(); this.service = service; } @Override public void run() { super.run(); service.printB(); } } } class Service4 { static public void printA() { synchronized (Service4.class) { try { System.out.println("线程:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入printA"); Thread.sleep(3000); System.out.println("线程:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开printA"); } catch (InterruptedException e) { e.printStackTrace(); } } } static public void printB() { synchronized (Service4.class) { System.out.println("线程:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入printB"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开printB"); } } }
运行结果如下:synchronized(class)代码块的作用和synchronized static的作用是一样的
以前我说过,synchronized还可以传入其他的实例对象或者方法的形参,那么我现在要说一种把synchronized(class)和String一起使用的特殊情况,还是用代码讲解,下面我附上一段代码,如下:
public static void main(String[] args) { Service5 service = new Service5(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); } public static class ThreadB extends Thread { private Service5 service; public ThreadB(Service5 service) { super(); this.service = service; } @Override public void run() { // TODO Auto-generated method stub super.run(); service.print("AA"); } } public static class ThreadA extends Thread { private Service5 service; public ThreadA(Service5 service) { super(); this.service = service; } @Override public void run() { // TODO Auto-generated method stub super.run(); service.print("AA"); } } } class Service5 { public static void print(String string) { try { synchronized (string) { while (true) { System.out.println(Thread.currentThread().getName()); Thread.sleep(1000); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果如下:可以看到输出结果会打印出无数个连续的A,这是由于在JVM中有String常量池缓存的功能,所以说printA()和printB()两个方法里传进来的“AA”是同一个值,因此两个线程持有相同的锁,所以总有一个线程执行不到。
上面已经看到了常量池带来的问题,因此大多情况下,都不用String最为对像锁,而改用其他的,比如new Object()实例化一个Object对象。可以看看下面的例子,运行后的区别在哪,如下:
public static void main(String[] args) { Service6 service = new Service6(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); } public static class ThreadB extends Thread { private Service6 service; public ThreadB(Service6 service) { super(); this.service = service; } @Override public void run() { // TODO Auto-generated method stub super.run(); service.print(new Object()); } } public static class ThreadA extends Thread { private Service6 service; public ThreadA(Service6 service) { super(); this.service = service; } @Override public void run() { // TODO Auto-generated method stub super.run(); service.print(new Object()); } } } class Service6 { public static void print(Object object) { try { synchronized (object) { while (true) { System.out.println(Thread.currentThread().getName()); Thread.sleep(1000); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果如下:可以看到运行结果是交叉的异步的,说明两个线程持有的锁不是同一把锁。
时间: 2024-10-03 13:52:26