synchronized和static synchronized的区别
当synchronized关键字修饰普通方法时,是对当前类的当前对象加上了锁,也就是对象锁,示例如下
public synchronized void a() {
String date= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
System.out.println("执行A之前的时间" + date);
try {
for (int i = 0; i < 5; i++) {
System.out.println("被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行");
Thread.sleep(1000);
}
String dateAfter= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
System.out.println("执行A之后的时间" + dateAfter);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void b() {
try {
String date= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
System.out.println("执行B之前的时间" + date);
for (int i = 0; i < 5; i++) {
System.out.println("被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行");
Thread.sleep(1000);
}
String dateAfter= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
System.out.println("执行B之后的时间" + dateAfter);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("被Synchronized关键字修饰的普通方法>>>>> B");
}
我们用关键字synchronized修饰了普通方法A和B,并让A、B方法都执行5s,下面看执行测试代码
public static void main(String[] args) {
SynchronizedDemo synchronizedOne = new SynchronizedDemo();
SynchronizedDemo synchronizedTwo = new SynchronizedDemo();
Thread one = new Thread(new Runnable() {
@Override
public void run() {
synchronizedOne.a();
// synchronizedOne.c();
}
});
Thread two = new Thread(new Runnable() {
@Override
public void run() {
try {
//休眠 为了A先执行
Thread.sleep(1000);
synchronizedOne.b();
// synchronizedTwo.d();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
one.start();
two.start();
}
创建了两个SynchronizedDemo类的对象synchronizedOne 、synchronizedTwo,先用同一个对象去执行a、b、e方法,运行效果(在执行B之前休眠1s,为了A先执行)
执行A之前的时间22:29:01
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
执行A之后的时间22:29:06
执行B之前的时间22:29:06
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
执行B之后的时间22:29:11
- 当用同一个对象正在访问该类中被
Synchronized修饰的普通方法时,其他线程的当前对象不可访问该类的其他同步方法
我们用同一个类的两个对象分类去访问A,B方法看看什么效果
执行A之前的时间22:38:28
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
执行B之前的时间22:38:29
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> A <<<<<正在执行
被Synchronized关键字修饰的普通方法>>>>> B <<<<<正在执行
执行A之后的时间22:38:33
执行B之后的时间22:38:34
被Synchronized关键字修饰的普通方法>>>>> B
- 同一个类不同对象的synchronized方法是不相干扰的。也就是说,其它线程可以同时访问同一个类的另一个对象的synchronized方法;
当synchronized关键字修饰静态方法时,是对当前类加上了锁,也就是类锁,同一时刻只能有一个线程访问该同步方法,其他线程阻塞,示例如下
public static synchronized void c() {
try {
String date= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
System.out.println("执行C之前的时间" + date);
for (int i = 0; i < 5; i++) {
System.out.println("被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行");
Thread.sleep(1000);
}
String dateAfter= new SimpleDateFormat("HH:mm:ss").format(new Date(System.currentTimeMillis()));
System.out.println("执行C之后的时间" + dateAfter);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void d() {
System.out.println("被Synchronized关键字修饰的静态方法>>>>> D");
}
用static synchronized修饰c,d方法,执行测试
Thread one = new Thread(new Runnable() {
@Override
public void run() {
synchronizedOne.c();
}
});
Thread two = new Thread(new Runnable() {
@Override
public void run() {
try {
//休眠 为了C先执行
Thread.sleep(1000);
synchronizedTwo.d();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
one.start();
two.start();
运行结果
执行C之前的时间22:57:15
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
被Synchronized关键字修饰的静态方法>>>>> C <<<<<正在执行
执行C之后的时间22:57:20
被Synchronized关键字修饰的静态方法>>>>> D
总结
- 修饰普通方法:普通方法属于对象性方法,该同步锁属于对象锁,多个线程中同一个对象访问同步方法,只能有一个线程访问,多个线程多个对象可以同时访问该同步方法
- 修饰静态方法:静态方法属于类方法,该同步锁属于类锁,多个线程多个对象只能有一个线程可以访问该同步方法,因为字节码文件只有一个。
- 修饰代码块:有Synchronized(obj)和Synchronized(obj.class)两种代码块,前者同修饰普通方法一样,或者同修饰静态方法一样。
同步方法与同步代码块的区别
同步方法的作用范围较大,会同步对象中所有的同步方法的代码。
同步代码块控制范围较小,只会同步代码块中的代码,而代码块意外的代码还是可以被多个线程同时访问的







网友评论