一、synchronized 同步方法:java
是对当前对象加锁。异步
package com.test; public class TestObject { synchronized public void methodA() { try { System.out.println("begin methodA threadName=" + Thread.currentThread().getName() + " beigin time = " + System.currentTimeMillis()); Thread.sleep(1000); System.out.println("end methodA endTime=" + System.currentTimeMillis()); } catch (Exception e) { e.printStackTrace(); } } public void methodB() { try { System.out.println("begin methodB threadName=" + Thread.currentThread().getName() + " beigin time = " + System.currentTimeMillis()); Thread.sleep(1000); System.out.println("end methodB endTime=" + System.currentTimeMillis()); } catch (Exception e) { e.printStackTrace(); } } }
package com.test; public class Run { public static void main(String[] args) { TestObject object = new TestObject(); Thread a = new Thread(new Runnable() { @Override public void run() { object.methodA(); } }); Thread b = new Thread(new Runnable() { @Override public void run() { object.methodB(); } }); a.start(); b.start(); } }
运行结果: begin methodA threadName=Thread-0 beigin time = 1527756573018 begin methodB threadName=Thread-1 beigin time = 1527756573018 end methodB endTime=1527756574018 end methodA endTime=1527756574018
经过上面的代码能够得知,虽然线程A先持有了object对象的锁,可是线程B彻底能够异步调用非synchronized类型的方法。ide
若是将TestObject.java 中的methodB()方法前加上synchronized关键字。this
#methodB()前加synchronized关键字运行结果: begin methodA threadName=Thread-0 beigin time = 1527756647320 end methodA endTime=1527756648321 begin methodB threadName=Thread-1 beigin time = 1527756648321 end methodB endTime=1527756649321
结论:spa
总结:线程
关键字synchronized 拥有锁重入的功能,也就是在使用synchronized时,但一个线程获得一个对象锁后,再次请求此对象锁时是能够再次获得该对象的锁的。code
同步不能够继承。对象
二、synchronized同步语句块:blog
是对某一个对象进行加锁。synchronized(this) 锁定的也是当前对象。继承
用关键字synchronized声明方法在某些状况下是有弊端的,好比A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长的时间。在这样的状况下可使用synchronized同步语句块来解决。
package com.test; public class Task { public void methodA() { try { synchronized (this) { System.out.println("A begin time = " + System.currentTimeMillis()); Thread.sleep(2000); System.out.println("A end time = " + System.currentTimeMillis()); } } catch (Exception e) { e.printStackTrace(); } } public void methodB() { try { synchronized (this) { System.out.println("B begin time = " + System.currentTimeMillis()); System.out.println("B end time = " + System.currentTimeMillis()); } } catch (Exception e) { e.printStackTrace(); } } }
package com.test; public class Run { public static void main(String[] args) { Task task = new Task(); Thread a = new Thread(new Runnable() { @Override public void run() { task.methodA(); } }); Thread b = new Thread(new Runnable() { @Override public void run() { task.methodB(); } }); a.start(); b.start(); } }
运行结果: A begin time = 1527757467600 A end time = 1527757469601 B begin time = 1527757469601 B end time = 1527757469601
在使用同步synchronized(this)代码块时须要注意的是,当一个线程访问object一个synchronized(this)同步代码块时,其余线程对同一个object中全部其余synchronized(this)同步代码块的访问将被阻塞,这说明synchronized使用的 对象监视器 是一个。
将任意对象做为对象监视器:
多个线程调用同一个对象中的不一样名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的阻塞的。
package com.test; public class Service { private String anyString = new String(); public void methodA() { try { synchronized (anyString) { System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块"); Thread.sleep(3000); System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块"); } } catch (Exception e) { e.printStackTrace(); } } }
package com.test; public class Run { public static void main(String[] args) { Service service = new Service(); Thread a = new Thread(new Runnable() { @Override public void run() { service.methodA(); } }); Thread b = new Thread(new Runnable() { @Override public void run() { service.methodA(); } }); a.start(); b.start(); } }
运行结果: 线程名为:Thread-1在1527758321295进入同步块 线程名为:Thread-1在1527758324295离开同步块 线程名为:Thread-0在1527758324295进入同步块 线程名为:Thread-0在1527758327295离开同步块
使用 synchronized(非this对象x)同步代码块进行同步操做时,对象监视器必须是同一个对象。若是不是同一个对象,运行的结果就是异步了。
把Service.java修改成以下:
package com.test; public class Service { private String anyString = new String(); public void methodA() { try { synchronized (anyString) { System.out.println("A begin"); Thread.sleep(3000); System.out.println("A end"); } } catch (Exception e) { e.printStackTrace(); } } synchronized public void methodB() { System.out.println("B begin"); System.out.println("B end"); } }
运行结果:
B begin
A begin
B end
A end
因为对象的监视器不一样,因此运行结果就是异步的。
三、静态同步synchronized方法与synchronized(class)代码块:
关键字synchronized还能够应用在static静态方法上,若是这样写,那就是对当前的*.java文件对应的class类进行加锁。
package com.test; public class Service { synchronized public static void methodA() { try { System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块"); Thread.sleep(3000); System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块"); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public static void methodB() { try { System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块"); Thread.sleep(3000); System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块"); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果: 线程名为:Thread-1在1527758944286进入同步块 线程名为:Thread-1在1527758947287离开同步块 线程名为:Thread-0在1527758947287进入同步块 线程名为:Thread-0在1527758950287离开同步块
synchronized关键字加到static静态方法上是给Class上锁,而synchronized关键字加到非static静态方法上是给对象上锁。因此同一个类下使用两种加锁方式的方法是能够进行异步调用的。