类锁:
可以锁住一个类里面被synchronized修饰的静态方法,他是全局统一的,当有多个线程访问多个实例的时候,如果这个时候一个线程使用了类锁,那么其他的线程如果执行到了被synchronized修饰的静态方法的时候就会进入等待
对象锁:
可以锁住一个类里面被synchronized修饰的普通方法,他不是全局统一的,当有多个线程访问多个对象的时候,这个时候线程1锁住了对象1,那么对于对象2来说是没有任何影响的,他们之间互不干扰,只有当线程3访问对象1的被synchronized修饰的普通方法的时候线程3会进入等待
下面是代码演示
对象锁:
一个对象,三个线程的时候
package com.thread;
import java.util.concurrent.TimeUnit;
public class SynTest {
public static void main(String[] args) {
A a = new A();
new Thread(() ->{
a.method01(); //A.method01();
}).start();
new Thread(() ->{
//为了保证先让程序执行 a.method01();方法,这里延时100ms
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
a.method02(); A.method02();
}).start();
new Thread(() ->{
//为了保证先让程序执行 a.method01();方法,这里延时100ms
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
a.method03(); A.method02();
}).start();
}
}
class A{
public synchronized void method01(){
//时停500ms
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是方法1");
}
public synchronized void method02(){
System.out.println("我是方法2");
}
public synchronized static void method03(){
System.out.println("我是方法3");
}
}
最后输出结果
最后执行结果是秒打印出方法3,然后过了3秒之后先打印了方法1在打印了方法2。
这里程序最早执行的是方法1,刚进入方法1的时候A的对象锁会被锁住,这个时候所有被synchronized修饰的普通方法都会被锁住,当有线程想执行这些方法的时候就会在方法外面阻塞,等里面的线程从方法里面出去之后才会进入执行。
这里的方法3是秒打印的,说明方法3没有被对象锁阻塞。对象锁无法锁静态方法
两个对象两个线程的时候
package com.thread;
import java.util.concurrent.TimeUnit;
public class SynTest {
public static void main(String[] args) {
A a = new A();
A a1 = new A();
new Thread(() ->{
a.method01();
}).start();
new Thread(() ->{
//为了保证先让程序执行 a.method01();方法,这里延时100ms
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
a1.method02();
}).start();
}
}
class A{
public synchronized void method01(){
//时停3s
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是方法1");
}
public synchronized void method02(){
System.out.println("我是方法2");
}
}
输出结果:
秒打印了我是方法2,然后打印了方法1,这就说明这里执行的a1.method02();没有被a.method01();阻塞,因为他们是两个对象,两个对象之间的对象锁互不干扰
类锁
一个对象三个线程的时候
package com.thread;
import java.util.concurrent.TimeUnit;
public class SynTest {
public static void main(String[] args) {
A a = new A();
new Thread(() ->{
a.method01(); //A.method01();
}).start();
new Thread(() ->{
//为了保证先让程序执行 a.method01();方法,这里延时100ms
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
a.method02(); A.method02();
}).start();
new Thread(() ->{
//为了保证先让程序执行 a.method01();方法,这里延时100ms
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
a.method03(); A.method02();
}).start();
}
}
class A{
public synchronized static void method01(){
//时停500ms
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是方法1");
}
public synchronized static void method02(){
System.out.println("我是方法2");
}
public synchronized void method03(){
System.out.println("我是方法3");
}
}
执行结果:
秒打印了方法3,然后过了3秒打印了方法1和方法2
这里程序最先执行的是方法1,方法1是被synchronized修饰的静态方法,当有线程执行这个方法的时候,这个对象的类锁就会被锁住,所有的被synchronized修饰的静态方法都会被锁住,当有线程想执行这些方法的时候,就会阻塞,所以方法2一直等到方法1执行完之后才执行,等了3s
这里方法3秒打印了出来,说明方法3没有被类锁锁住,也就是说类锁对于非静态方法无效
两个线程两个对象的时候
package com.thread;
import java.util.concurrent.TimeUnit;
public class SynTest {
public static void main(String[] args) {
A a = new A();
A a1 = new A();
new Thread(() ->{
a.method01(); //A.method01();
}).start();
new Thread(() ->{
//为了保证先让程序执行 a.method01();方法,这里延时100ms
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
a1.method02(); A.method02();
}).start();
}
}
class A{
public synchronized static void method01(){
//时停500ms
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是方法1");
}
public synchronized static void method02(){
System.out.println("我是方法2");
}
}
执行结果:
等了3s之后打印出了方法1和方法2,说明方法2被阻塞了
程序还是先执行的a.method01();这个方法,当线程1执行这个方法的时候类锁会触发,所有的被synchronized修饰的静态方法都会被锁住。
类锁和对象锁代码块的写法
//对象锁
synchronized (this){
}
//类锁
synchronized (A.class){
}