java 方法锁 对象锁_Java的类锁、对象锁和方法锁

本文详细介绍了 Java 中的 synchronized 关键字在多线程环境下的应用,包括对象锁和类锁。通过实例展示了同步方法和同步代码块的不同行为:不同对象的同步方法不会阻塞,同一对象的同步方法会阻塞;不同对象的 this 修饰的同步代码块不会阻塞,而类锁(静态同步方法和类锁代码块)则会导致阻塞。最后讨论了类锁和对象锁同时存在时的情况,表明它们不会相互阻塞。
摘要由CSDN通过智能技术生成

在Java中,对于synchronized关键字,大家看到的第一反应就是这个关键字是进行同步操作的,即得名“同步锁”。

当用它来修饰方法和代码块时,默认当前的对象为锁的对象,即对象锁。

当用来修饰类和静态方法时,默认当前的类为锁的对象

对象锁

修饰在方法上时,多个线程调用同一对象的同步方法时会阻塞,调用不同对象的同步方法时不会阻塞。

在多线程环境下,调用不同对象的同步方法:

public class SynchronizedDemo {

public synchronized void synTest(){

int i = 5;

while (i-- > 0){

System.out.println(Thread.currentThread().getName() + " : " + i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public static void main(String[] args) {

SynchronizedDemo demo1 = new SynchronizedDemo();

SynchronizedDemo demo2 = new SynchronizedDemo();

Thread t1 = new Thread(new Runnable() {

@Override

public void run() {

demo1.obj3();

}

});

Thread t2 = new Thread(new Runnable() {

@Override

public void run() {

demo2.obj3();

}

});

t1.start();

t2.start();

}

}

Output:

Thread-0 : 4

Thread-1 : 4

Thread-0 : 3

Thread-1 : 3

Thread-0 : 2

Thread-1 : 2

Thread-0 : 1

Thread-1 : 1

Thread-0 : 0

Thread-1 : 0

在多线程环境下,调用同一对象的同步方法:

public class SynchronizedDemo {

public synchronized void synTest(){

int i = 5;

while (i-- > 0){

System.out.println(Thread.currentThread().getName() + " : " + i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public static void main(String[] args) {

SynchronizedDemo demo1 = new SynchronizedDemo();

SynchronizedDemo demo2 = new SynchronizedDemo();

Thread t1 = new Thread(new Runnable() {

@Override

public void run() {

demo1.synTest();

}

});

Thread t2 = new Thread(new Runnable() {

@Override

public void run() {

demo1.synTest();

}

});

t1.start();

t2.start();

}

}

Output:

Thread-0 : 4

Thread-0 : 3

Thread-0 : 2

Thread-0 : 1

Thread-0 : 0

Thread-1 : 4

Thread-1 : 3

Thread-1 : 2

Thread-1 : 1

Thread-1 : 0

在多线程环境下,调用不同对象通过this修饰的局部代码块

public class SynchronizedDemo {

public void synTest(){

synchronized (this){

int i = 5;

while (i-- > 0){

System.out.println(Thread.currentThread().getName() + " : " + i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public static void main(String[] args) {

SynchronizedDemo demo1 = new SynchronizedDemo();

SynchronizedDemo demo2 = new SynchronizedDemo();

Thread t1 = new Thread(new Runnable() {

@Override

public void run() {

demo1.synTest();

}

});

Thread t2 = new Thread(new Runnable() {

@Override

public void run() {

demo2.synTest();

}

});

t1.start();

t2.start();

}

}

Output:

Thread-0 : 4

Thread-1 : 4

Thread-0 : 3

Thread-1 : 3

Thread-0 : 2

Thread-1 : 2

Thread-0 : 1

Thread-1 : 1

Thread-0 : 0

Thread-1 : 0

对于this修饰的其实指的就是类的实例,所以它也属于对象锁,并不是类锁。

在多线程环境下,调用不同对象通过其他实例类修饰的局部代码块

public class SynchronizedDemo {

public void synTest(){

String str = new String("lock");

synchronized (str){

int i = 5;

while (i-- > 0){

System.out.println(Thread.currentThread().getName() + " : " + i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public static void main(String[] args) {

SynchronizedDemo demo1 = new SynchronizedDemo();

SynchronizedDemo demo2 = new SynchronizedDemo();

Thread t1 = new Thread(() -> {

demo1.synTest();

});

Thread t2 = new Thread(() -> {

demo2.synTest();

});

t1.start();

t2.start();

}

}

Output:

Thread-0 : 4

Thread-1 : 4

Thread-1 : 3

Thread-0 : 3

Thread-1 : 2

Thread-0 : 2

Thread-1 : 1

Thread-0 : 1

Thread-1 : 0

Thread-0 : 0

我们可以看到,我们通过每次调用时实例一个String来进行同步代码块,但是并没有发生阻塞,因为每次生成的是一个实例String,锁的是String,每次都是不一样的,所以不会发生阻塞。

可以通过上述的运行结果可以得到一下结论:

在多线程环境下:

调用不同对象的同步方法,不会发生阻塞

调用相同对象的同步方法,会发生阻塞

调用不同对象通过this修饰的局部代码块,不会发生阻塞

调用不同对象通过其他实例类修饰的同步代码块,不会发生阻塞

类锁

在多线程环境下,多次调用类的静态同步方法:

public class SynchronizedDemo {

public static synchronized void synTest(){

int i = 5;

while (i-- > 0){

System.out.println(Thread.currentThread().getName() + " : " + i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public static void main(String[] args) {

Thread t1 = new Thread(new Runnable() {

@Override

public void run() {

SynchronizedDemo.synTest();

}

});

Thread t2 = new Thread(new Runnable() {

@Override

public void run() {

SynchronizedDemo.synTest();

}

});

t1.start();

t2.start();

}

Output:

Thread-0 : 4

Thread-0 : 3

Thread-0 : 2

Thread-0 : 1

Thread-0 : 0

Thread-1 : 4

Thread-1 : 3

Thread-1 : 2

Thread-1 : 1

Thread-1 : 0

在多线程环境下,多次调用被类锁的代码块:

public class SynchronizedDemo {

public void synTest(){

synchronized (SynchronizedDemo.class){

int i = 5;

while (i-- > 0){

System.out.println(Thread.currentThread().getName() + " : " + i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public static void main(String[] args) {

SynchronizedDemo demo1 = new SynchronizedDemo();

SynchronizedDemo demo2 = new SynchronizedDemo();

Thread t1 = new Thread(new Runnable() {

@Override

public void run() {

demo1.synTest();

}

});

Thread t2 = new Thread(new Runnable() {

@Override

public void run() {

demo2.synTest();

}

});

t1.start();

t2.start();

}

}

Output:

Thread-1 : 4

Thread-1 : 3

Thread-1 : 2

Thread-1 : 1

Thread-1 : 0

Thread-0 : 4

Thread-0 : 3

Thread-0 : 2

Thread-0 : 1

Thread-0 : 0

对于对象SynchronizedDemo.class,实际上就是SynchronizedDemo这个类,也就是对类进行加锁。

可以通过上述的运行结果可以得到一下结论:

在多线程环境下:

多次调用静态的同步方法,会进行阻塞

不同对象调用被类锁的同步代码块,会进行阻塞

类锁和对象锁同时存在

在多线程环境下,同时调用同一对象的类锁和对象锁

public class SynchronizedDemo {

public static synchronized void synTestStatic() {

int i = 5;

while (i-- > 0) {

System.out.println(Thread.currentThread().getName() + " : " + i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public synchronized void synTest() {

int i = 5;

while (i-- > 0) {

System.out.println(Thread.currentThread().getName() + " : " + i);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public static void main(String[] args) {

SynchronizedDemo demo1 = new SynchronizedDemo();

Thread t1 = new Thread(() -> {

demo1.synTest();

});

Thread t2 = new Thread(() -> {

SynchronizedDemo.synTestStatic();

});

t1.start();

t2.start();

}

}

Output:

Thread-1 : 4

Thread-0 : 4

Thread-1 : 3

Thread-0 : 3

Thread-1 : 2

Thread-0 : 2

Thread-1 : 1

Thread-0 : 1

Thread-1 : 0

Thread-0 : 0

我们可以到看到,在多线程环境下,类锁和对象锁同时存在的情况下,多线程访问时不会阻塞,因为他们不是同一个锁。

可以通过上述的运行结果可以得到一下结论:

在多线程环境下:

类锁和对象锁同时存在的情况下,不会发生阻塞

总结

762d18bd7f8f1bb3a9638423582c4c10.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值