文章目录
- 前言
- 一、Synchronized修饰非静态方法
- 二、Synchronized修饰静态方法
- 三、类锁和对象锁的访问是不冲突的
- 四、总结
前言
直接说结论:
1.Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。
2.Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。
3.对于类锁synchronized static,是通过该类直接调用加类锁的方法,而对象锁是创建对象调用加对象锁的方法,两者访问是不冲突的,对于同一类型锁锁住的方法,同一对象是无法同时访问的.
一、Synchronized修饰非静态方法
Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。
如果采用形象的比喻就是,对于这个对象可能有很多方法(房间),有一些加了锁(锁门的房间),而这些房间共用一把钥匙,导致当一个被锁方法被访问时,无法访问其他带锁的方法。
但是需要注意:一个对象可以拿一把钥匙,多个对象可以插队执行。
考虑下图代码,想一下会输出什么。
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void getTwo(){
System.out.println("two");
}
}
答案是输出one two
因为getOne()虽然要停止2秒,但上了对象锁,getTwo()不能超车(访问),要等getOne()被调用完,把钥匙换回来,才能继续执行
二、Synchronized修饰静态方法
Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。
类对象只有一个,只在郊外有这一栋别墅,里面的静态方法也被一把锁管着。因为一个类对象只能拿一把锁。
将两个方法都设为static,猜猜会输出什么
package JUC_test;
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void getTwo(){
System.out.println("two");
}
}
输出one two
也可以不new对象直接类对象调用
package JUC_test;
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
// number.getOne();
Number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// number.getTwo();
Number.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void getTwo(){
System.out.println("two");
}
}
答案是 one two
显然,这次我们直接插队进别墅大门失败了,很好地解释了类锁
三、类锁和对象锁的访问是不冲突的
现在我们设定为one静态,two非静态,猜猜会发生什么
package JUC_test;
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
// number.getOne();
Number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
// Number.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void getTwo(){
System.out.println("two");
}
}
答案是 two one
你开别墅大门,关我别墅内的狗窝什么事?
package JUC_test;
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
// Number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// number.getTwo();
Number.getTwo();
}
}).start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void getTwo(){
System.out.println("two");
}
}
答案是 two one
同理,你开狗窝大门,关我别墅什么事?
四、总结
对于synchronized修饰方法的调用
我们考虑了
非静态 非静态
静态 静态
静态 非静态
非静态 静态
四种情况,
可以留下思考,如果这些换成两个对象去调用呢?
答案会是什么呢?
two one
one two(有两个实例对象,但只有一个类对象)
two one
two one