java中的每个对象和每个类都有锁,而且是互斥锁,也就是说只能有一方占有,另一方只能等到对方释放后才能再占有锁。synchronized关键字就是基于java的对象和类的锁的。

synchronized关键字可以修饰方法,也可以修饰代码块,修饰代码块时一共有以下5种用法。

一、this

synchronized(this){
//互斥代码
}

这里的this指的是执行这段代码的对象,synchronized得到的锁就是this这个对象的锁,这种写法等价于:

public synchronized void func(){
//互斥代码
}

二、A.class

synchronized(A.class){
//互斥代码
}

这里A.class得到的是A这类,所以synchronized关键字得到的锁是类的锁,这种方法同下面的方法功能是相同的:

public static synchronized void fun(){
//互斥代码
}

所有需要类的锁的方法等不能同时执行,但是它和需要某个对象的锁的方法或者是不需要任何锁的方法可以同时执行。

三、object.getClass()

synchronized(object.getClass){
//互斥代码
}

这种方法一般情况下同第二种是相同,但是出现继承和多态时,得到的结果却是不相同的。所以一般情况下推荐使用A.class的方式。

四、object

synchronized(object){
//互斥代码
}

这里synchronized关键字拿到的锁是对象object的锁,所有需要这个对象的锁的方法都不能同时执行。

public class Trans {
private Object lock = new Object();

public void printNum(int num){
synchronized (lock) {
System.out.print(Thread.currentThread());
for(int i=0;i<25;i++){
System.out.print(i+" ");
}
System.out.println();
}
}
}
class MyThread implements Runnable {  
private Trans trans;
private int num;

public MyThread(Trans trans, int num) {
this.trans = trans;
this.num = num;
}

public void run() {
while (true)
{
trans.printNum(num);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

public class Test {
public static void main(String[] args) {
Trans t = new Trans();
Trans t1 = new Trans();
Thread a = new Thread(new MyThread(t, 1));
Thread b = new Thread(new MyThread(t1, 2));

a.start();
b.start();
}
}

在上边的例子中试图使用这种方法达到互斥方法打印方法,但是事实是这样做是没有效果的,因为每个Trans对象都有自己的Object对象,这两个对象都有自己的锁,所以两个线程需要的是不同锁,两个锁之间没有任何相互作用,所以不会起到互斥作用。

五、static object

上边的代码稍作修改就可以起到互斥作用,将Trans类中Object对象的声明改为下面这样:

private static Object lock = new Object();

这样不同的类使用的就是同一个object对象,需要的锁也是同一个锁,就可以达到互斥的效果了。

经过两篇博客的介绍,我们详细的讨论了synchronized关键字的用法,看似非常复杂,其实抓住要点之后还是很好区分的,只要看synchronized获得的是哪个对象或者类的锁就行啦,其他需要这个锁的方法都不能同时执行,不需要这个锁的方法都能同时执行。

最后还要告别一个误区,相信大家都不会再犯这种错误了,synchronized锁住的是一个对象或者类(其实也是对象),而不是方法或者代码段。