java并发的一些细节
并发的细节
本文只想说明3个结论
1、synchronized关键字使用MONITORENTER、MONITOREXIT指令实现。
2、多个线程由于synchronized等待,那么执行顺序是FILO。
3、使用ReentrantLock是正常队列FIFO顺序。
如果您对细节感兴趣可以细看。
示例
关键java并发的一个小细节。先从一段代码说起。
public void doWork(String id) {
synchronized (this) {
if (StringUtils.isEmpty(id)) {
try {
Thread.sleep(1000 * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName());
}
}
synchronized原理
上面是一段非常简单控制并发的java代码。从class字节码可以看到使用了MONITORENTER、MONITOREXIT两个关键指令。
// access flags 0x1
public doWork(Ljava/lang/String;)V //对应方法
// parameter id
TRYCATCHBLOCK L0 L1 L2 java/lang/InterruptedException
TRYCATCHBLOCK L3 L4 L5 null
TRYCATCHBLOCK L5 L6 L5 null
L7
LINENUMBER 7 L7
ALOAD 0 //加载this变量
DUP //运行区数据作为Raw Type数据,压入栈顶
ASTORE 2 //this 到局部变量3
MONITORENTER //对应的synchronized
L3
LINENUMBER 8 L3
ALOAD 1 //加载局部变量 id
INVOKESTATIC org/apache/commons/lang3/StringUtils.isEmpty (Ljava/lang/CharSequence;)Z
//调用静态方法
IFEQ L8 //通过栈顶数值判断
L0
LINENUMBER 10 L0
LDC 10000 //加载常量至栈顶
INVOKESTATIC java/lang/Thread.sleep (J)V //静态方法
L1
LINENUMBER 13 L1
GOTO L8
L2
LINENUMBER 11 L2
FRAME FULL [com/ruijie/groupview/port/adpter/web/contorllers/A java/lang/String java/lang/Object] [java/lang/InterruptedException]
ASTORE 3 //第三个变量到栈顶
L9
LINENUMBER 12 L9 //打印异常信息
ALOAD 3 //加载第三个变量
INVOKEVIRTUAL java/lang/InterruptedException.printStackTrace ()V
L8 // 打印线程名
LINENUMBER 15 L8
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
INVOKESTATIC java/lang/Thread.currentThread ()Ljava/lang/Thread;
INVOKEVIRTUAL java/lang/Thread.getName ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L10
LINENUMBER 16 L10 //原文第16行,方法执行完毕。
ALOAD 2
MONITOREXIT //退出monitor
L4
GOTO L11
L5
FRAME SAME1 java/lang/Throwable
ASTORE 4
ALOAD 2
MONITOREXIT //异常退出monitor
L6
ALOAD 4
ATHROW //异常
L11
LINENUMBER 17 L11
FRAME CHOP 1
RETURN //返回
L12
//常量
LOCALVARIABLE e Ljava/lang/InterruptedException; L9 L8 3
LOCALVARIABLE this Lcom/ruijie/groupview
