8. 静态同步synchronized方法与synchronized(class)代码块
关键字synchronized还可以应用static静态方法上,如果这样写,那是对当前的.java文件对应的Class类进行持锁。*
下面通过通过例子说明一下用法与效果。
(1) Service.java
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");
}
}
(2) ThreadA.java
public class ThreadA extends Thread {
@Override
public void run() {
Service.printA();
}
}
(3) ThreadB.java
public class ThreadB extends Thread {
@Override
public void run() {
Service.printB();
}
}
(4) Run.java
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();
}
}
线程名称为:A在1634056855437进入printA
--线程名称为:A在1634056858458离开printA
线程名称为:B在1634056858458进入printB
线程名称为:B在1634056858459离开printB
从运行结果来看,并没有什么特别之处,都是同步的效果,和将synchronized关键字加到非static方法上使用的效果是一样的。其实还是有本质上的不同的,synchronized关键字加到static静态方法上是给Class类上锁,而synchronized关键字加到非static静态方法上是对象上锁。
为了证明不是同一个锁,我们可以通过下面的实验来验证:
(1) Service.java
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");
}
}
(2) ThreadA.java
public class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.printA();
}
}
(3) ThreadB.java
public class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.printB();
}
}
(4) ThreadC.java
public class ThreadC extends Thread {
private Service service;
public ThreadC(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.printC();
}
}
(5) Run.java
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();
}
}
执行结果:
线程名称为:A在1634056663156进入printA
线程名称为:C在1634056663157进入printC
????线程名称为:C在1634056663185离开printC
----线程名称为:A在1634056666186离开printA
线程名称为:B在1634056666186进入printB
线程名称为:B在1634056666186离开printB
实验结果说明:这个实验实际上设置了两个锁:
- 对象锁:printC是非静态方法,受对象锁的约束
- Class锁:PrintA、PrintB是静态方法,都被同一个Class约束
还可以将上述Service.java代码中的PrintB改为:
synchronized public void printB() {
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printB");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printB");
}
重新运行,结果如下:
线程名称为:B在1634058460652进入printB
线程名称为:A在1634058460652进入printA
----线程名称为:A在1634058461681离开printA
线程名称为:B在1634058465681离开printB
线程名称为:C在1634058465681进入printC
????线程名称为:C在1634058465682离开printC
PrintB和PrintC都是非静态的,属于同一个锁,所以C要等待B结束后释放锁。
异步的原因是持有不同的锁,一个是对象锁,另外一个是Class锁,而Class锁对类的所有对象实例起作用。
同步synchronized(class)代码块的作用其实和synchronized static方法的作用一样。
通过下面的示例(省略Thread文件)验证这一点:
(1) Service.java
public class Service {
public static void printA() {
synchronized (Service.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();
}
}
}
public static void printB() {
synchronized (Service.class) {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printB");
System.out.println("++++线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printB");
}
}
}
(2)Run.java
public class Run {
public static void main(String[] args) {
Service service1 = new Service();
Service service2 = new Service();
ThreadA a = new ThreadA(service1);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service2);
b.setName("B");
b.start();
}
}
执行结果:
线程名称为:A在1634098725887进入printA
----线程名称为:A在1634098728911离开printA
线程名称为:B在1634098728911进入printB
++++线程名称为:B在1634098728912离开printB