所以我们在用synchronized关键字的时候,能缩小代码段的范围尽量缩小,能在代码段上加同步不要再整个方法上加同步。这叫减小锁的粒度,使代码更大程度的并发。原因是基于以上的思想,锁的代码段太长了,别的线程是不是要等很久,等的花儿都谢了。当然这段是题外话,与本文核心思想并无太大关联。

  再看上面的代码,每个线程中都new了一个Sync类的对象,也是产生了三个Sync对象,由于不是同一个对象,所以可以多线程同时运行synchronized方法或代码段。

  为了验证上述的观点,修改一下代码,让三个线程使用同一个Sync的对象。

class MyThread extends Thread {

 private Sync sync;

 public MyThread(Sync sync) {
  this.sync = sync;
 }

 public void run() {
  sync.test();
 }
}

public class Main {

 public static void main(String[] args) {
  Sync sync = new Sync();
  for (int i = 0; i < 3; i++) {
   Thread thread = new MyThread(sync);
   thread.start();
  }
 }
}

  运行结果:

  test开始..
  test结束..
  test开始..
  test结束..
  test开始..
  test结束..

  可以看到,此时的synchronized方法和synchronized代码段都起了作用。

  那么,如果真的想锁住这段代码,要怎么做?也是,如果还是开始的那段代码,每个线程new一个Sync对象,怎么才能让test方法不会被多线程执行。

  解决也很简单,只要锁住同一个对象不行了。例如,synchronized后的括号中锁一个static final对象,这样行了。这样是没问题,但是,比较多的做法是让synchronized锁这个类对应的Class对象。

class Sync {

 public void test() {
  synchronized (Sync.class) {
   System.out.println("test开始..");
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("test结束..");
  }
 }
}

class MyThread extends Thread {

 public void run() {
  Sync sync = new Sync();
  sync.test();
 }
}

public class Main {

 public static void main(String[] args) {
  for (int i = 0; i < 3; i++) {
   Thread thread = new MyThread();
   thread.start();
  }
 }
}

  运行结果:

  test开始..
  test结束..
  test开始..
  test结束..
  test开始..
  test结束..

  上面代码用synchronized(Sync.class)实现了全局锁的效果。

  后说说static synchronized,实际上static方法可以直接类名加方法名调用,方法里面没有this这个概念,所以,static synchronized方法也相当于全局锁,相当于锁住了代码段。