当前位置: 首页 > 科技观察

同步锁This和Class的区别!

时间:2023-03-14 08:59:55 科技观察

本文转载自微信公众号“Java中文社区”,作者雷哥。转载本文请联系Java中文社区公众号。Synchronized是Java语言处理并发问题的常用手段。它也被亲切地称为“Java内置锁”,可见其地位之高。但是,synchronized有很多用途。当它修饰不同的对象时,其含义也不同。让我们一起来看看吧。synchronized用法synchronized可以用来修饰普通方法、静态方法和代码块。①公共方法修饰/***同步修饰公共方法*/publicsynchronizedvoidmethod(){//...}synchronized修饰公共方法时,被修饰的方法称为同步方法,其作用范围为整个方法,动作的对象就是调用这个方法的对象。②修饰静态方法/***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=newSynchronizedExample();//创建5个线程来performtasksfor(inti=0;i<5;i++){newThread(newRunnable(){@Overridepublicvoidrun(){try{//调用同步修改类方法example.classMethod();}catch(InterruptedExceptione){e.printStackTrace();}}}).start();}}/***同步修改类方法*@throwsInterruptedException*/publicvoidclassMethod()throwsInterruptedException{synchronized(SynchronizedExample.class){System.out.println(String.format("currentexecutionthread:%s,executiontime:%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();//调用synchronized修饰的类方法example.classMethod();}catch(InterruptedExceptione){e.printStackTrace();}}}).start();}}/***同步修改类方法*@throwsInterruptedException*/publicvoidclassMethod()throwsInterruptedException{synchronized(SynchronizedExample.class){System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(),newDate()));TimeUnit.SECONDS.sleep(1);}}}以上程序的执行结果如下:从上面的结果我们可以看出,虽然是不同的对象,但是还是使用了同一个锁。3.锁定这个共享一个类实例接下来,我们创建5个线程并调用synchronized来锁定这个例子。首先,我们的五个线程调用同一个对象的加锁方法。示例代码如下:importjava.util.Date;importjava.util.concurrent.TimeUnit;publicclassSynchronizedExample{publicstaticvoidmain(String[]args){//创建当前类实例finalSynchronizedExampleexample=newSynchronizedExample();//创建5个线程执行任务for(inti=0;i<5;i++){newThread(newRunnable(){@Overridepublicvoidrun(){try{//Callthismethodmodifiedbysynchronizedexample.thisMethod();}catch(InterruptedExceptione){e.printStackTrace();}}}).start();}}/***同步修改了这个方法*@throwsInterruptedException*/publicvoidthisMethod()throwsInterruptedException{synchronized(this){System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(),newDate()));TimeUnit.SECONDS.sleep(1);}}}上面程序的执行结果如下:从上面的结果可以看出,上面的线程都使用了同一个锁。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();//调用synchronized修饰的this方法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给一个类加锁的时候,无论是共享一个对象还是创建多个对象,都是使用同一个锁,而使用synchronized给this加锁,只有相同的对象才会使用同样的锁,不同对象之间的锁是不同的。