Java的类锁、对象锁和方法锁
程序员文章站
2022-10-04 09:18:11
在Java中,对于synchronized关键字,大家看到的第一反应就是这个关键字是进行同步操作的,即得名“同步锁”。 当用它来修饰方法和代码块时,默认当前的对象为锁的对象,即对象锁。 当用来修饰类和静态方法时,默认当前的类为锁的对象 对象锁 修饰在方法上时,多个线程调用同一对象的同步方法时会阻塞, ......
在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
我们可以到看到,在多线程环境下,类锁和对象锁同时存在的情况下,多线程访问时不会阻塞,因为他们不是同一个锁。
可以通过上述的运行结果可以得到一下结论:
在多线程环境下:
- 类锁和对象锁同时存在的情况下,不会发生阻塞