java同步方法和同步代码块的区别

同步代码块:

package threads.ex1;

class KitchenSync {
	private int[] intArray = new int[10];

	void reverseOrder() {
		synchronized (this) {
			int halfWay = intArray.length / 2;
			for (int i = 0; i < halfWay; ++i) {
				int upperIndex = intArray.length - 1 - i;
				int save = intArray[upperIndex];
				intArray[upperIndex] = intArray[i];
				intArray[i] = save;
			}
		}
	}
}


反编译后的字节码:

E:\Java\code\jvm\bin\threads\ex1>javap -verbose KitchenSync
Compiled from "KitchenSync.java"
class threads.ex1.KitchenSync extends java.lang.Object
  SourceFile: "KitchenSync.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = class        #2;     //  threads/ex1/KitchenSync
const #2 = Asciz        threads/ex1/KitchenSync;
const #3 = class        #4;     //  java/lang/Object
const #4 = Asciz        java/lang/Object;
const #5 = Asciz        intArray;
const #6 = Asciz        [I;
const #7 = Asciz        <init>;
const #8 = Asciz        ()V;
const #9 = Asciz        Code;
const #10 = Method      #3.#11; //  java/lang/Object."<init>":()V
const #11 = NameAndType #7:#8;//  "<init>":()V
const #12 = Field       #1.#13; //  threads/ex1/KitchenSync.intArray:[I
const #13 = NameAndType #5:#6;//  intArray:[I
const #14 = Asciz       LineNumberTable;
const #15 = Asciz       LocalVariableTable;
const #16 = Asciz       this;
const #17 = Asciz       Lthreads/ex1/KitchenSync;;
const #18 = Asciz       reverseOrder;
const #19 = Asciz       halfWay;
const #20 = Asciz       I;
const #21 = Asciz       i;
const #22 = Asciz       upperIndex;
const #23 = Asciz       save;
const #24 = Asciz       StackMapTable;
const #25 = class       #26;    //  java/lang/Throwable
const #26 = Asciz       java/lang/Throwable;
const #27 = Asciz       SourceFile;
const #28 = Asciz       KitchenSync.java;

{
threads.ex1.KitchenSync();
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #10; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   bipush  10
   7:   newarray int
   9:   putfield        #12; //Field intArray:[I
   12:  return
  LineNumberTable:
   line 3: 0
   line 4: 4
   line 3: 12

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      13      0    this       Lthreads/ex1/KitchenSync;


void reverseOrder();
  Code:
   Stack=4, Locals=6, Args_size=1
   0:   aload_0
   1:   dup
   2:   astore_1
   3:   monitorenter
   4:   aload_0
   5:   getfield        #12; //Field intArray:[I
   8:   arraylength
   9:   iconst_2
   10:  idiv
   11:  istore_2
   12:  iconst_0
   13:  istore_3
   14:  goto    61
   17:  aload_0
   18:  getfield        #12; //Field intArray:[I
   21:  arraylength
   22:  iconst_1
   23:  isub
   24:  iload_3
   25:  isub
   26:  istore  4
   28:  aload_0
   29:  getfield        #12; //Field intArray:[I
   32:  iload   4
   34:  iaload
   35:  istore  5
   37:  aload_0
   38:  getfield        #12; //Field intArray:[I
   41:  iload   4
   43:  aload_0
   44:  getfield        #12; //Field intArray:[I
   47:  iload_3
   48:  iaload
   49:  iastore
   50:  aload_0
   51:  getfield        #12; //Field intArray:[I
   54:  iload_3
   55:  iload   5
   57:  iastore
   58:  iinc    3, 1
   61:  iload_3
   62:  iload_2
   63:  if_icmplt       17
   66:  aload_1
   67:  monitorexit
   68:  goto    74
   71:  aload_1
   72:  monitorexit
   73:  athrow
   74:  return
  Exception table:
   from   to  target type
     4    68    71   any
    71    73    71   any
  LineNumberTable:
   line 7: 0
   line 8: 4
   line 9: 12
   line 10: 17
   line 11: 28
   line 12: 37
   line 13: 50
   line 9: 58
   line 7: 66
   line 16: 74

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      75      0    this       Lthreads/ex1/KitchenSync;
   12      54      2    halfWay       I
   14      52      3    i       I
   28      30      4    upperIndex       I
   37      21      5    save       I

  StackMapTable: number_of_entries = 4
   frame_type = 254 /* append */
     offset_delta = 17
     locals = [ class threads/ex1/KitchenSync, int, int ]
   frame_type = 43 /* same */
   frame_type = 255 /* full_frame */
     offset_delta = 9
     locals = [ class threads/ex1/KitchenSync, class threads/ex1/KitchenSync ]
     stack = [ class java/lang/Throwable ]
   frame_type = 250 /* chop */
     offset_delta = 2


}

分析

方法内的同步语句会使用两个指令:

monitorenterc2 objectref →enter monitor for object ("grab the lock" - start of synchronized() section)
monitorexitc3 objectref →exit monitor for object ("release the lock" - end of synchronized() section)

当java虚拟机遇到monitorenter的时候,它获得栈中objectref所引用的对象的锁。如果线程已经拥有了那个对象的锁,锁的计数器会加1。线程中每条monitorexit指令都会引起计数器减1。当计数器变成0的时候,监视器就释放了。

而且return后,还有Exception table。


同步方法:

package threads.ex1;

class HeatSync {
	private int[] intArray = new int[10];

	synchronized void reverseOrder() {
		int halfWay = intArray.length / 2;
		for (int i = 0; i < halfWay; ++i) {
			int upperIndex = intArray.length - 1 - i;
			int save = intArray[upperIndex];
			intArray[upperIndex] = intArray[i];
			intArray[i] = save;
		}
	}
}

反编译后的字节码:

E:\Java\code\jvm\bin\threads\ex1>javap -verbose HeatSync
Compiled from "HeatSync.java"
class threads.ex1.HeatSync extends java.lang.Object
  SourceFile: "HeatSync.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = class        #2;     //  threads/ex1/HeatSync
const #2 = Asciz        threads/ex1/HeatSync;
const #3 = class        #4;     //  java/lang/Object
const #4 = Asciz        java/lang/Object;
const #5 = Asciz        intArray;
const #6 = Asciz        [I;
const #7 = Asciz        <init>;
const #8 = Asciz        ()V;
const #9 = Asciz        Code;
const #10 = Method      #3.#11; //  java/lang/Object."<init>":()V
const #11 = NameAndType #7:#8;//  "<init>":()V
const #12 = Field       #1.#13; //  threads/ex1/HeatSync.intArray:[I
const #13 = NameAndType #5:#6;//  intArray:[I
const #14 = Asciz       LineNumberTable;
const #15 = Asciz       LocalVariableTable;
const #16 = Asciz       this;
const #17 = Asciz       Lthreads/ex1/HeatSync;;
const #18 = Asciz       reverseOrder;
const #19 = Asciz       halfWay;
const #20 = Asciz       I;
const #21 = Asciz       i;
const #22 = Asciz       upperIndex;
const #23 = Asciz       save;
const #24 = Asciz       StackMapTable;
const #25 = Asciz       SourceFile;
const #26 = Asciz       HeatSync.java;

{
threads.ex1.HeatSync();
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #10; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   bipush  10
   7:   newarray int
   9:   putfield        #12; //Field intArray:[I
   12:  return
  LineNumberTable:
   line 3: 0
   line 4: 4
   line 3: 12

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      13      0    this       Lthreads/ex1/HeatSync;


synchronized void reverseOrder();
  Code:
   Stack=4, Locals=5, Args_size=1
   0:   aload_0
   1:   getfield        #12; //Field intArray:[I
   4:   arraylength
   5:   iconst_2
   6:   idiv
   7:   istore_1
   8:   iconst_0
   9:   istore_2
   10:  goto    54
   13:  aload_0
   14:  getfield        #12; //Field intArray:[I
   17:  arraylength
   18:  iconst_1
   19:  isub
   20:  iload_2
   21:  isub
   22:  istore_3
   23:  aload_0
   24:  getfield        #12; //Field intArray:[I
   27:  iload_3
   28:  iaload
   29:  istore  4
   31:  aload_0
   32:  getfield        #12; //Field intArray:[I
   35:  iload_3
   36:  aload_0
   37:  getfield        #12; //Field intArray:[I
   40:  iload_2
   41:  iaload
   42:  iastore
   43:  aload_0
   44:  getfield        #12; //Field intArray:[I
   47:  iload_2
   48:  iload   4
   50:  iastore
   51:  iinc    2, 1
   54:  iload_2
   55:  iload_1
   56:  if_icmplt       13
   59:  return
  LineNumberTable:
   line 7: 0
   line 8: 8
   line 9: 13
   line 10: 23
   line 11: 31
   line 12: 43
   line 8: 51
   line 14: 59

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      60      0    this       Lthreads/ex1/HeatSync;
   8      52      1    halfWay       I
   10      49      2    i       I
   23      28      3    upperIndex       I
   31      20      4    save       I

  StackMapTable: number_of_entries = 2
   frame_type = 253 /* append */
     offset_delta = 13
     locals = [ int, int ]
   frame_type = 40 /* same */


}

分析

可以看到,同步方法没有使用monitorenter和monitorexit这两个指令。

方法return后也没有Exception table。

当虚拟机解析对方法的符号引用时,它判断这个方法是否是同步的。如果是同步的,虚拟机就在调用方法之前获取一个锁。


总结

因此,同步方法比同步代码块更高效,但是它们的功能是一样的。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值