需要明确的几个问题:
- synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果 再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
- 无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
- 每个对象只有一个锁(lock)与之相关联。
- 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
synchronized关键字的作用域有二种:
- 某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线 程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的 synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
- 某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
1、使用在方法上synchronized aMethod(){...}
使用相同的 object
public class synchTest { private String a= ""; private List<String> b= new ArrayList<>(); // 方法一 public void job() { System.out.println("job ....."); synchronized (b){ System.out.println("job 使用锁中 ...."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } System.out.println("job end....."); } // 方法二 public synchronized void job2(){ System.out.println("job2 ....."); synchronized (b){ System.out.println("job22 使用锁中 ..."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } System.out.println("job2 end....."); } public static void main(String[] args) { final synchTest rs = new synchTest(); new Thread() { public void run() { rs.job(); } }.start(); new Thread() { public void run() { rs.job2(); } }.start(); } } 结果: job ..... job 使用锁中 .... job2 ..... job end..... job22 使用锁中 ... job2 end.....
使用不同的object
public class synchTest { private String a= ""; private List<String> b= new ArrayList<>(); // 方法一 public void job() { System.out.println("job ....."); synchronized (a){ System.out.println("job 使用锁中 ...."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } System.out.println("job end....."); } // 方法二 public synchronized void job2(){ System.out.println("job2 ....."); synchronized (b){ System.out.println("job22 使用锁中 ..."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } System.out.println("job2 end....."); } public static void main(String[] args) { final synchTest rs = new synchTest(); new Thread() { public void run() { rs.job(); } }.start(); new Thread() { public void run() { rs.job2(); } }.start(); } } 结果: job ..... job 使用锁中 .... job2 ..... job22 使用锁中 ... job end..... job2 end.....
使用this关键词
public class synchTest { private String a= ""; private List<String> b= new ArrayList<>(); // 方法一 public void job() { System.out.println("job ....."); synchronized (this){ System.out.println("job 使用锁中 ...."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } System.out.println("job end....."); } // 方法二 public synchronized void job2(){ System.out.println("job2 ....."); synchronized (b){ System.out.println("job22 使用锁中 ..."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } System.out.println("job2 end....."); } public static void main(String[] args) { final synchTest rs = new synchTest(); new Thread() { public void run() { rs.job(); } }.start(); new Thread() { public void run() { rs.job2(); } }.start(); } } 结果: job ..... job 使用锁中 .... job end..... job2 ..... job22 使用锁中 ... job2 end.....
结论:
- synchronized(Object) object相同的情况下,修饰的内容会同步,等上一个执行完才能执行下一个方法的内容
- synchronized(Object) object不相同的情况下,修饰内容不会同步,两个方法可以一起执行
- this这个比较特殊,如果先执行修饰this这个方法的内容,会同步,否则 不会同步(可以测试下)
2、使用在方法内部 synchronized(Oject){...}
public class synchTest { // 方法一 public synchronized void job() { System.out.println("job ....."); System.out.println("job 使用锁中 ...."); try { Thread.sleep(2000); } catch (InterruptedException e) { } System.out.println("job end....."); } // 方法二 public synchronized void job2(){ System.out.println("job2 ....."); System.out.println("job22 使用锁中 ..."); try { Thread.sleep(2000); } catch (InterruptedException e) { } System.out.println("job2 end....."); } public static void main(String[] args) { final synchTest rs = new synchTest(); new Thread() { public void run() { rs.job(); } }.start(); new Thread() { public void run() { rs.job2(); } }.start(); } } 结果: job ..... job 使用锁中 .... job end..... job2 ..... job22 使用锁中 ... job2 end.....
结论:
- 对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法,在对象内容所有的synchronized 的方法都会同步,必须等上一个方法执行完才能执行下一个方法
2、使用在方法内部 synchronized(Oject){...}、synchronized aMethod(){...}混用
public class synchTest { public String a = ""; // 方法一 public void job() { System.out.println("job ....."); synchronized (a){ System.out.println("job 使用锁中 ...."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } System.out.println("job end....."); } // 方法二 public synchronized void job2(){ System.out.println("job2 ....."); System.out.println("job22 使用锁中 ..."); try { Thread.sleep(2000); } catch (InterruptedException e) { } System.out.println("job2 end....."); } public static void main(String[] args) { final synchTest rs = new synchTest(); new Thread() { public void run() { rs.job(); } }.start(); new Thread() { public void run() { rs.job2(); } }.start(); } } 结果: job ..... job 使用锁中 .... job2 ..... job22 使用锁中 ... job end..... job2 end.....
结论:
对象实例内 synchronized aMethod(){} 与synchronized(Object) 不会相互同步