synchronized是Java语言中处理并发问题的常用方法。它也被亲切地称为“Java内置锁”,可见其地位之高。但是,synchronized有很多用途。当它修饰不同的对象时,其含义也不同。让我们一起来看看吧。synchronized用法synchronized可以用来修饰普通方法、静态方法和代码块。①修饰普通方法/***synchronized修饰普通方法*/publicsynchronizedvoidmethod(){//......}当synchronized修饰普通方法时,被修饰的方法称为同步方法,其范围action就是整个方法,action的对象就是调用这个方法的对象。②修饰静态方法/***synchronized修饰静态方法*/publicstaticsynchronizedvoidstaticMethod(){//......}synchronized修饰静态方法时,其作用范围是整个方法,函数对象就是调用这个类的所有对象。③修饰代码块为了减小锁的粒度,我们可以选择使用synchronized在一个方法的某部分修改(一个代码块),从而实现对一个方法中部分代码的加锁。实现代码如下:publicvoidclassMethod()throwsInterruptedException{//前置码...//锁码synchronized(SynchronizedExample.class){//...}//后置码...}当执行上述代码,修改后的代码块称为同步语句块,其作用范围为花括号“{}”括起来的代码块,作用对象为调用该代码块的对象。但是上面的代码,除了给class加锁,还可以给this加锁,具体例子如下:publicvoidclassMethod()throwsInterruptedException{//预处理代码...synchronized(this){//......}//后处理代码...}那么问题来了,用synchronized锁this和class有什么区别?他们不都锁定同一个班级吗?答案真的是否定的,锁定this和class还是有很大区别的。下面通过4个例子来看看两者的区别。1.锁定类共享一个类实例首先,我们创建5个线程,调用同一个对象下的synchronized锁定类代码。具体示例如下:importjava.util.Date;importjava.util.concurrent.TimeUnit;publicclassSynchronizedExample{publicstaticvoidmain(String[]args){//创建当前类实例finalSynchronizedExampleexample=new同步示例();//创建5个线程执行任务for(inti=0;i<5;i++){newThread(newRunnable(){@Overridepublicvoidrun(){try{//调用同步修饰类方法示例。classMethod();}catch(InterruptedExceptione){e.printStackTrace();}}}).start();}}/***synchronized修饰的类方法*@throwsInterruptedException*/publicvoidclassMethod()throwsInterruptedException{synchronized(SynchronizedExample.class){System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(),newDate()));TimeUnit.SECONDS.sleep(1);}}}上面程序的执行结果如下:从上面的结果可以看出5个线程共享同一个锁2、锁定类创建多个实例接下来我们创建5个线程,分别调用不同对象下的synchronized锁定类代码。具体示例如下:importjava.util.Date;importjava.util.concurrent.TimeUnit;publicclassSynchronizedExample{publicstaticvoidmain(String[]args){//创建5个线程执行任务for(inti=0;i<5;i++){newThread(newRunnable(){@Overridepublicvoidrun(){try{//创建一个类实例SynchronizedExampleexample=newSynchronizedExample();//调用同步修饰的类方法example.classMethod();}catch(InterruptedExceptione){e.printStackTrace();}}}).start();}}/***synchronized修饰的类方法*@throwsInterruptedException*/publicvoidclassMethod()throwsInterruptedException{synchronized(SynchronizedExample.class){System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(),newDate()));TimeUnit.SECONDS.sleep(1);上面程序的执行结果如下:从上面的结果可以看出,虽然是不同的对象,但是还是使用了同一个锁3.Lockthis共享一个类实例接下来,我们创建5threads并调用synchronized来锁定这个例子。首先,我们的五个线程调用同一个对象的加锁方法。示例代码如下:importjava.util.Date;importjava.util.concurrent.TimeUnit;publicclassSynchronizedExample{publicstaticvoidmain(String[]args){//创建当前类实例finalSynchronizedExampleexample=new同步示例();//创建5个线程执行任务for(inti=0;i<5;i++){newThread(newRunnable(){@Overridepublicvoidrun(){try{//调用synchronized修改过的this方法实例。thisMethod();}catch(InterruptedExceptione){e.printStackTrace();}}}).start();}}/***synchronized修改了这个方法*@throwsInterruptedException*/publicvoidthisMethod()throwsInterruptedException{synchronized(this){System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(),newDate()));TimeUnit.SECONDS.sleep(1);}}}上面程序的执行结果如下:从上面的结果可以看出,上面的线程使用了同一个put锁4.锁定它以创建多个类实例。最后一个例子最为特殊。我们用synchronized把这个锁住,让这5个线程调用各自的对象创建方法。具体例子如下:importjava.util.Date;importjava.util.concurrent.TimeUnit;publicclassSynchronizedExample{publicstaticvoidmain(String[]args){//创建5个线程执行任务for(inti=0;i<5;i++){newThread(newRunnable(){@Overridepublicvoidrun(){try{//创建(多个)类实例SynchronizedExampleexample=newSynchronizedExample();//调用此方法修改通过同步example.thisMethod();}catch(InterruptedExceptione){e.printStackTrace();}}}).start();}}/***这个方法被synchronized修饰*@throwsInterruptedException*/publicvoidthisMethod()throwsInterruptedException{synchronized(this){System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(),newDate()));TimeUnit.SECONDS.sleep(1);上面程序的执行结果如下:从上面的结果可以看出,在使用synchronized给this加锁的时候,如果线程调用的不是同一个对象,那么这些线程之间使用的锁是独立的锁,这个结果和synchronized加锁类的结果完全不一样总结通过上面4个例子,我们可以得出结论,在使用synchronized加锁类的时候,无论是共享一个对象还是创建多个对象,他们使用的都是同一个锁,但是用synchronized给this加锁的时候,只有同一个对象才会使用同一个锁,不同对象之间的锁是不一样的。本系列推荐文章与并发第一课:Thread解释了Java中用户线程和守护线程的区别那么多?深入理解ThreadPool线程池的7种创建方式,强烈推荐大家使用……池化技术到底有多牛?看到线程和线程池的对比,惊呆了!并发中的线程同步以及volatile锁和synchronized锁的区别。轻量级锁就一定比重量级锁快吗?这样终止线程会导致服务宕机?SimpleDateFormat线程不安全的5个解决方案!ThreadLocal不好用?这就是你没用的原因!ThreadLocal内存溢出代码演示及原因分析!信号量告白:限流器我用对了!CountDownLatch:别招手了,等大家再次加入我们!CyclicBarrier:当所有人都准备好后,司机就可以发动汽车了!关注公众号“Java中文社区”,查看更多有趣的Java并发知识文章。
