多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的,阻塞的。
这说明synchronized同步方法或synchronized(this)同步代码块分别有两种作用
(1)synchronized同步方法
1)对其他synchronized同步方法或synchronized(this)同步代码块调用呈阻塞状态
2)同一时间只有一个线程可以执行synchronized同步方法中的代码
(2)synchronized(this)同步代码块
1)对其他synchronized同步方法或synchronized(this)同步代码块调用呈阻塞状态
2)同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码
Java还支持对“任意对象”作为“对象监视器”来实现同步的功能。这个“任意对象”大多数是实例变量及方法的参数,使用synchronized(非this对象)
synchronized(非this对象)格式的作用只有1中:synchronized(非this对象x)同步代码块
1)在多个线程持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象x)同步代码块中的代码
2)当持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象x)同步代码块中的代码。
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class Service { private String usernameParam; private String passwordParam; private String anyString = new String(); public void setUsernamePassword(String username,String password){ try{ synchronized (anyString){ System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入同步"); usernameParam = username; Thread.sleep(2000); passwordParam = password; System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开同步"); } }catch(InterruptedException e){ e.printStackTrace(); } } }
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadA extends Thread { private Service service; public ThreadA(Service service){ super(); this.service = service; } public void run(){ service.setUsernamePassword("a","aa"); } }
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadB extends Thread { private Service service; public ThreadB(Service service){ super(); this.service = service; } public void run(){ service.setUsernamePassword("b","bb"); } }
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class Run { public static void main(String [] args){ Service service = new Service(); ThreadA threadA = new ThreadA(service); threadA.setName("A"); threadA.start(); ThreadB threadB = new ThreadB(service); threadB.setName("B"); threadB.start(); threadB.start(); } }
线程名称为:A在1484823811547进入同步
线程名称为:A在1484823813559离开同步
线程名称为:B在1484823813559进入同步
线程名称为:B在1484823815573离开同步
如果修改service.java为
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class Service { private String usernameParam; private String passwordParam; public void setUsernamePassword(String username,String password){ try{ String anyString = new String(); synchronized (anyString){ System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入同步"); usernameParam = username; Thread.sleep(2000); passwordParam = password; System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开同步"); } }catch(InterruptedException e){ e.printStackTrace(); } } }
线程名称为:A在1484823870625进入同步
线程名称为:B在1484823870625进入同步
线程名称为:B在1484823872638离开同步
线程名称为:A在1484823872638离开同步
所以,使用synchronized(非this对象)同步代码块格式进行同步操作时,对象监视器必须是同一个对象,如果不是同一个对象监视器,运行的结果就是异步调用了,就会交叉运行。
再看下一个示例:
package synBlockString2; /** * Created by Administrator on 2017/1/19 0019. */ public class Service { private String anyThing = new String(); public void a(){ try { synchronized (anyThing){ System.out.println("a begin"); Thread.sleep(2000); System.out.println("a end"); } } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void b(){ System.out.println(" b begin"); System.out.println(" b end"); } }
package synBlockString2; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadA extends Thread { private Service service; public ThreadA(Service service){ super(); this.service = service; } public void run(){ service.a(); } }
package synBlockString2; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadB extends Thread { private Service service; public ThreadB(Service service){ super(); this.service = service ; } public void run(){ service.b(); } }
package synBlockString2; /** * Created by Administrator on 2017/1/19 0019. */ public class Run { public static void main(String [] args){ Service service = new Service(); ThreadA threadA = new ThreadA(service); threadA.setName("A"); threadA.start(); ThreadB threadB = new ThreadB(service); threadB.setName("B"); threadB.start(); } }
运行结果:
a begin
b begin
b end
a end
由于对象监视器不同,所以运行结果就是异步的
同步代码块放在非同步synchronized方法中进行声明,并不能保证调用方法的线程的执行同步/顺序性,也就是线程调用方法的顺序是无序的,虽然在同步块中执行的顺序是同步的,这样就容易出现脏读问题。