这个也是我在面试中被问到的一个题目(synchronize修饰静态方法和非静态方法的区别),这个没答出来
关键字synchronized还可以应用在static静态方法上,如果这样写,那是对当前的*.java文件对应的Class类进行持锁,测试项目:类文件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) {
// TODO Auto-generated catch block
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的代码:
public class ThreadA extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Service.PrintA();
}
}
ThreadB:
public class ThreadB extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Service.PrintB();
}
}
运行测试代码:
public class Test1 {
public static void main(String[] args) throws InterruptedException {
ThreadA a = new ThreadA();
a.setName("A");
a.start();
ThreadB b = new ThreadB();
b.setName("B");
b.start();
}
}
运行结果:
从运行结果来看,并没有什么特别地方,都是同步的效果,和将synchronized关键字加到非静态static方法上使用的效果是一样的,其实还是有本质上的不同,synchronized关键字加到static静态方法上是给Class类上锁,而synchronized关键字加到非static静态方法上是给对象上锁:
为了验证不是同一个锁。创建新的 项目,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) {
// TODO Auto-generated catch block
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() + "进入printB");
System.out.println("线程的名称为:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printB");
}
}
ThreadA :
public class ThreadA extends Thread{
private Service service;
public ThreadA(Service service) {
// TODO Auto-generated constructor stub
super();
this.service = service;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.PrintA();
}
}
ThreadB:
public class ThreadB extends Thread{
private Service service;
public ThreadB(Service service) {
// TODO Auto-generated constructor stub
super();
this.service = service;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.PrintB();
}
}
ThreadC:
public class ThreadC extends Thread{
private Service service;
public ThreadC(Service service) {
// TODO Auto-generated constructor stub
super();
this.service = service;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.PrintC();
}
}
测试代码类:
public class Test1 {
public static void main(String[] args) throws InterruptedException {
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();
}
}
运行结果:
结果产生异步的原因是持有不同的锁,一个是对象锁,一个是Class锁,而Class锁可以对类的所有对象实例起作用。如果不是Class锁的话,则多个实例就有多个锁,上文章有说到。下面验证Class锁对所有的实例起作用
修改运行测试文件如下:
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
Service service2 = new Service();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service2);
b.setName("B");
b.start();
}
}
运行结果:
由结果来看,依然是同步进行的,也就是说明了Class锁对所有实例起作用。
同步Synchronized(class) 的实质其实和synchronized static 方法一样,都是给Class加锁。验证:
修改Service代码:
public class Service {
public 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) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void PrintB() {
synchronized (Service.class) {
System.out.println("线程的名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printB");
System.out.println("线程的名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printB");
}
}
}
注意:PrintA和PrintB方法加不加static都一样了这时
再次运行代码得:
结论:静态同步synchronized方法与synchronized(class)代码块效果一样,没有本质上的区别,与非静态的方法比起来,非静态的是给对象上锁。多个对象的时候会给多个对象上锁。依旧是异步的。而静态的方法,则因为持有的是Class锁,所以多个对象创建的时候,因为其Class依旧是一样的,所有就会是同步状态