上QQ阅读APP看书,第一时间看更新
2.2.14 静态同步:synchronized方法与synchronized(class)代码块
synchronized关键字还可以应用在静态方法上,如果这样写,那是对当前的*.java文件对应的Class类的对象进行持锁,Class类的对象是单例的,更具体地说,在静态方法上使用synchronized关键字声明同步方法时,是使用当前静态方法所在类对应Class类的单例对象作为锁的。
测试项目在synStaticMethod中,类文件Service.java代码如下:
package service; public class Service { synchronized public static void printA() { 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(); } } synchronized public static void printB() { System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入printB"); System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开printB"); } }
自定义线程类ThreadA.java代码如下:
package extthread; import service.Service; public class ThreadA extends Thread { @Override public void run() { Service.printA(); } }
自定义线程类ThreadB.java代码如下:
package extthread; import service.Service; public class ThreadB extends Thread { @Override public void run() { Service.printB(); } }
运行类Run.java代码如下:
package test; import service.Service; import extthread.ThreadA; import extthread.ThreadB; public class Run { public static void main(String[] args) { ThreadA a = new ThreadA(); a.setName("A"); a.start(); ThreadB b = new ThreadB(); b.setName("B"); b.start(); } }
程序运行结果如图2-43所示。
图2-43 运行结果是同步效果
虽然运行结果与将synchronized关键字加到非static静态方法上的使用效果一样,都是同步的效果,但还是有本质上的不同。synchronized关键字加到static静态方法上是将Class类的对象作为锁,而synchronized关键字加到非static静态方法上是将方法所在类的对象作为锁。
为了验证不是同一个锁,创建新的项目synTwoLock,文件Service.java代码如下:
package service; public class Service { synchronized public static void printA() { 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(); } } synchronized public static void printB() { System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入printB"); System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开printB"); } synchronized public void printC() { System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入printC"); System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开printC"); } }
自定义线程类ThreadA.java代码如下:
package extthread; import service.Service; public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.printA(); } }
自定义线程类ThreadB.java代码如下:
package extthread; import service.Service; public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.printB(); } }
自定义线程类ThreadC.java代码如下:
package extthread; import service.Service; public class ThreadC extends Thread { private Service service; public ThreadC(Service service) { super(); this.service = service; } @Override public void run() { service.printC(); } }
运行类Run.java代码如下:
package test; import service.Service; import extthread.ThreadA; import extthread.ThreadB; import extthread.ThreadC; public class Run { public static void main(String[] args) { Service service = new Service(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); ThreadC c = new ThreadC(service); c.setName("C"); c.start(); } }
程序运行结果如图2-44所示。
图2-44 printC()方法为异步运行
异步的原因是持有不同的锁,一个是将Service类的对象作为锁,另一个是将Service类对应Class类的对象作为锁,线程AB和C是异步的关系,而线程A和B是同步的关系。