一、什么是对象锁
对象锁也叫方法锁,是针对一个对象实例的,它只在该对象的某个内存位置声明一个标识该对象是否拥有锁,所有它只会锁住当前的对象,而并不会对其他对象实例的锁产生任何影响,不同对象访问同一个被synchronized修饰的方法的时候不会阻塞,
二、什么是类锁
类锁是锁住整个类,当有多个线程来声明这个类的对象时候将会被阻塞,直到拥有这个类锁的对象呗销毁或者主动释放了类锁,这个时候在被阻塞的线程被挑选出一个占有该类锁,声明该类的对象。其他线程继续被阻塞住,简单概况不管多少个对象,多少个对象,共用一把多,且只有一把,不管怎么调用,都会同步。
三、对象锁代码示例
第一种对象锁。创建MyObject对象,在method1方法前加上synchronized
public class MyObject {
public synchronized void method1(){
try {
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
String dateStr=simpleDateFormat.format(new Date());
System.out.println("线程名称:"+Thread.currentThread().getName()+" 执行时间:"+dateStr);
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
第二种对象锁
public class MyObject {
public void method1(){
try {
synchronized (this){
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
String dateStr=simpleDateFormat.format(new Date());
System.out.println("线程名称:"+Thread.currentThread().getName()+" 执行时间:"+dateStr);
Thread.sleep(4000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行测试类,两个线程调用同一个对象的同一个方法。
public class Test {
public static void main(String[] args) {
//创建一个对象
final MyObject myObject=new MyObject();
Thread t1=new Thread (new Runnable() {
@Override
public void run() {
myObject.method1();
}
},"t1");
Thread t2=new Thread (new Runnable() {
@Override
public void run() {
myObject.method1();
}
},"t2");
t1.start();
t2.start();
}
}
输出结果:
线程名称:t1 执行时间:2020-06-09 10:35:03
线程名称:t2 执行时间:2020-06-09 10:35:07
synchronized修饰普通方法,即为对象锁,那么这个时候,多个线程访问同一个对象实例的这个方法时,是会同步的,并且只有一个线程执行完,另一个线程才会执行
即,打印t1等待 4秒之后,t2才会打印,因为两个线程调用的是同一个对象实例的方法,即同一把锁,所有会同步执行
而如果是不同对象实例的话,则没有影响,因为两个线程调用的是不同实例的锁方法,即不是同一把锁,没有关系,所以会正常输出,不会同步
代码如下:
public class Test {
public static void main(String[] args) {
//创建两个对象
final MyObject myObject=new MyObject();
final MyObject myObject01=new MyObject();
Thread t1=new Thread (new Runnable() {
@Override
public void run() {
myObject.method1();
}
},"t1");
Thread t2=new Thread (new Runnable() {
@Override
public void run() {
myObject01.method1();
}
},"t2");
t1.start();
t2.start();
}
}
输出结果:
线程名称:t2 执行时间:2020-06-09 10:41:57
线程名称:t1 执行时间:2020-06-09 10:41:57
两个线程时间一致,相互没有受影响。
四、类锁代码示例
第一种方法。
public class MyObject {
public static synchronized void method1(){
try {
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
String dateStr=simpleDateFormat.format(new Date());
System.out.println("线程名称:"+Thread.currentThread().getName()+" 执行时间:"+dateStr);
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
第二种方式。
public class MyObject {
public void method1(){
try {
synchronized (MyObject.class){
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
String dateStr=simpleDateFormat.format(new Date());
System.out.println("线程名称:"+Thread.currentThread().getName()+" 执行时间:"+dateStr);
Thread.sleep(4000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行测试类
public class Test {
public static void main(String[] args) {
//创建两个对象
final MyObject myObject=new MyObject();
final MyObject myObject01=new MyObject();
Thread t1=new Thread (new Runnable() {
@Override
public void run() {
myObject.method1();
}
},"t1");
Thread t2=new Thread (new Runnable() {
@Override
public void run() {
myObject01.method1();
}
},"t2");
t1.start();
t2.start();
}
}
输出结果:
线程名称:t1 执行时间:2020-06-09 10:53:15
线程名称:t2 执行时间:2020-06-09 10:53:19
结论:
如果在static方法上修饰synchronized表示锁定了class类.多个线程都是相同的一把锁,即
取得的锁都是对象锁,哪个线程先执行代码,哪个线程就持有该方法所属的对象锁,其他对象就无法执行