说到锁机制,不得不提到Thread线程,而又不得不提到synchronized关键字,这个单词的意思是表示“同步”的意思。用它去修饰方法函数的时候,如果有多个线程同时调用这个方法函数的时候,那么当一个线程获得锁的时候,其他的线程只能进入等待队列,直到这根线程执行完毕,释放锁的时候,其他线程才可以获得锁去执行这个方法函数。
这里我们主要讲的是对象锁和类锁。对象锁,顾名思义,即为对象级别的锁,一个对象一个锁,不论为这个对象创建多少个线程。类锁,同样的意思,即为类级别的锁,一个类一个锁,这个类的所有对象共有一个锁。这两个锁在形式上的区别是类锁会有一个static关键字修饰。
下面来看看具体的例子,先定义一个具有对象锁和类锁的Demo类:
package com.Jevin.thread;
public class Demo {
//对象锁:
public synchronized void test01(){
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//类锁:
public static synchronized void test02(){
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我们先创建一个对象两个线程去调用对象锁,观察一下执行情况:
package com.Jevin.thread;
public class ObjectLock {
public static void main(String[] args){
//定义一个对象:
Demo d=new Demo();
//创建线程对象:
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
d.test01();
}
},"t1");
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
d.test01();
}
},"t2");
//启动线程:
t1.start();
t2.start();
}
}
执行情况:线程t1先执行,过了3秒钟后,线程t2再开始执行。那为什么呢?我的看法是:我们只创建了一个Demo对象,这个在堆中的对象包含了我们的对象锁的test01方法,两个线程进入同步块中,符合线程的执行规律。
那么,我们创建两个对象,会发生什么现象呢?如下所示:
package com.Jevin.thread;
public class ObjectLock {
public static void main(String[] args){
//定义一个对象:
Demo d1=new Demo();
Demo d2=new Demo();
//创建线程对象:
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
d1.test01();
}
},"t1");
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
d2.test01();
}
},"t2");
//启动线程:
t1.start();
t2.start();
}
}
执行结果是:t1线程和t2线程同时执行,我的看法是:我们创建了两个对象,这两个对象各拥有自己的test01方法函数,线程t1中的t1引用调用自己堆中的对象的test01方法,线程t2中的引用t2调用自己堆中的test01方法,各自互不影响,所以不会出现线程等待那种情况。
那么,问题来了,我去调用有static关键字修饰的test02方法,会怎样呢?答案是,不论一个对象,还是两个对象,或是n个对象,都会出先线程等待,线程一个一个的调用,为什么呢?我觉得:有static关键字修饰的方法,已经从对象级别上升到类级别了,所以,不论多少对象,都共有这个方法,所以才出现这种不论多少对象都会线程等待的现象。