用关键字synchronized声明的方法在是存在弊端的,在业务场景上来说比如一个线程执行很长时间的任务,那么另外一个线程只能等待,对于高并发就显得力不从心。这样的情况下可以使用synchronized同步语句块来解决,synchronized方法是对当前的对象进行枷锁,而synchronized代码块是对某一个对象进行枷锁。
当两个线程访问同一个对象object中的synchronize同步代码块时,一段时间内只能有一个线程被执行,另外一个线程必须等待当前线程执行完这个代码块后才能执行该代码块。
synchronized代码块间的同步性。
当一个线程访问object的一个synchronized同步代码块时,其他线程对于同一个object中的其他synchronized同步代码块的访问将被阻塞。
public class ObjectService { public void serviceMethodA() { try { synchronized (this) { System.out.println("A begin time=" + System.currentTimeMillis()); Thread.sleep(2000); System.out.println("A end end=" + System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } public void serviceMethodB() { synchronized (this) { System.out.println("B begin time=" + System.currentTimeMillis()); System.out.println("B end end=" + System.currentTimeMillis()); } } }
public class ThreadA extends Thread { private ObjectService service; public ThreadA(ObjectService service) { super(); this.service = service; } @Override public void run() { super.run(); service.serviceMethodA(); } }
public class ThreadB extends Thread { private ObjectService service; public ThreadB(ObjectService service) { super(); this.service = service; } @Override public void run() { super.run(); service.serviceMethodB(); } }
public class Run { public static void main(String[] args) { ObjectService service = new ObjectService(); ThreadA a = new ThreadA(service); a.setName("a"); a.start(); ThreadB b = new ThreadB(service); b.setName("b"); b.start(); } }
结论和synchronized方法一样,synchronized代码块也是锁定的当前对象。
总结:多个线程调用同一个对象中的不同名称的synchronized同步方法或则synchronized同步代码快时,调用的效果就是同步的,阻塞的。
在前面的介绍中使用的都是synchronized(this)格式来同步代码块,其实java还支持对“任意 对象”作为对象监视器,来实现同步的功能。这个任意对象 大多数是实例变量及方法的参数, 格式 synchronized(非this对象)。
public class Service { private String usernameParam; private String passwordParam;
String anyString = new String();
public void setUsernamePassword(String username, String password) {try {//2:synchronized (anyString) {System.out.println("线程名称为:" + Thread.currentThread().getName()+ "在" + System.currentTimeMillis() + "进入同步块");usernameParam = username;Thread.sleep(3000);passwordParam = password;System.out.println("线程名称为:" + Thread.currentThread().getName()+ "在" + System.currentTimeMillis() + "离开同步块");}} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.setUsernamePassword("a", "aa"); }
public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.setUsernamePassword("b", "bb"); } }
public class Run { public static void main(String[] args) { Service service = new Service(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); }
运行结果上图 两个线程持有的锁对象相同 所以同步执行
把service中的
String anyString = new String();
放到方法内部中 则运行结果:异步执行 两个线程分别创建锁对象
下面验证使用 synchronized(非this对象) 同步代码块 和synchronized(this对象)持有不同的对象监视器。
public class Service { private String anyString = new String(); public void a() { try { synchronized (anyString) { System.out.println("a begin"); Thread.sleep(3000); System.out.println("a end"); } } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void b() { System.out.println("b begin"); System.out.println("b end"); } }
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.a(); } } public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.b(); } }
public class Run { public static void main(String[] args) { Service service = new Service(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); } }
由于对象的监视器不同,所以运行的结果就是异步执行的。
总结如下:
1)当多个线程同时执行synchronized(x){}同步代码块时成同步的效果。(不在赘述)
2)当其他线程执行x对象中的synchronized同步方法时成同步的效果。代码如下:
public class ThreadA extends Thread { private Service service; private MyObject object; public ThreadA(Service service, MyObject object) { super(); this.service = service; this.object = object; } @Override public void run() { super.run(); service.testMethod1(object); } }
public class ThreadB extends Thread { private MyObject object; public ThreadB(MyObject object) { super(); this.object = object; } @Override public void run() { super.run(); object.speedPrintString(); } }
public class Run { public static void main(String[] args) throws InterruptedException { Service service = new Service(); MyObject object = new MyObject(); ThreadA a = new ThreadA(service, object); a.setName("a"); a.start(); Thread.sleep(100); ThreadB b = new ThreadB(object); b.setName("b"); b.start(); } }
public class MyObject { synchronized public void speedPrintString() { System.out.println("speedPrintString ____getLock time=" + System.currentTimeMillis() + " run ThreadName=" + Thread.currentThread().getName()); System.out.println("-----------------"); System.out.println("speedPrintString releaseLock time=" + System.currentTimeMillis() + " run ThreadName=" + Thread.currentThread().getName()); } }
3)当其他线程执行x对象方法里面的synchronized(this)代码块时也呈现同步的效果