Javaのロックオン

Javaのインタビュー、「ロック」がバインドされているときは常にものを挙げることにします。だから、インタビューの中で、私たちは何をすべきかについて話して、あなたが理解するのに十分な「ロック」することを教えているかどうかだろう「ロック」について話しますか?

この記事では、ロックの基本的な原理を分析し、アプリケーションのシナリオをロックすることを目指しています。

一、同期

1、顔の質問

2つの同期方法ライタとオブジェクト内の同じオブジェクトを読者アクセスがA、B二つのスレッドであり、相互に排他的な製造のだろうか?

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
      
      
クラス {
int型の A = 0 ;
公共 同期 ボイド ライター() {
睡眠(10)。
++;
}
公共 同期 ボイド リーダー() {
int i = a;
}
public static void main(String[] args) {
Test test = new Test();
new Thread(() -> {
test.writer();
}).start();
sleep( 1);
new Thread(() -> {
test.reader();
}).start();
}
}

答案:会。因为synchronized修饰的是方法,锁是对象锁,默认当前的对象作为锁的对象。只有当A释放锁之后,B才会获得对象的锁。

(1)如果是换成是不同对象呢?

不会互斥,因为锁的是对象,而不是方法

(2)如果writer、reader方法加上static修饰,两个线程中,类直接调用两个方法呢?

会互斥,因为锁的是Class对象。

(3)如果writer方法用static修饰,reader方法不用呢?

不会互斥。因为一个是对象锁,一个是Class对象锁,锁的类型不同。

synchronized修饰位置与锁的关系

  • 同步方法 —— 对象锁,当前实例对象
  • 静态同步方法 —— 类对象锁,当前对象的Class对象
  • 同步方法块 —— 对象锁,synchonized括号里配置的对象

二、锁的底层实现

思考几个问题

  1. 对象锁、Class对象锁时如何实现的
  2. 为什么要这么设计,只设计一个对象锁或Class对象锁,有什么不好?

1、反编译

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
      
      
class {
static int a = 0;
public synchronized void writer() {
System.out.println( "writer方法开始调用");
a++;
waitNs( 20);
System.out.println( "writer方法调用结束");
}
public static synchronized void reader() {
System.out.println( "reader方法开始调用");
int i = a;
System.out.println( "reader方法调用结束");
}
public void writer2() {
synchronized ( this) {
a--;
}
}
}

使用javacjavap -verbose命令,反编译上述代码

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
      
      
...
{
static int a;
descriptor: I
flags: ACC_STATIC
public com.fonxian.entity.LockDemo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
//同步方法
public synchronized void writer();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String writer方法开始调用
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #5 // Field a:I
11: iconst_1
12: iadd
13: putstatic #5 // Field a:I
16: bipush 20
18: invokestatic #6 // Method waitNs:(I)V
21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
24: ldc #7 // String writer方法调用结束
26: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: return
LineNumberTable:
line 11: 0
line 12: 8
line 13: 16
line 14: 21
line 15: 29
//静态同步方法
public static synchronized void reader();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=0
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #8 // String reader方法开始调用
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #5 // Field a:I
11: istore_0
12: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #9 // String reader方法调用结束
17: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: return
LineNumberTable:
line 18: 0
line 19: 8
line 20: 12
line 21: 20
//同步代码块
public void writer2();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: getstatic #5 // Field a:I
7: iconst_1
8: isub
9: putstatic #5 // Field a:I
12: aload_1
13: monitorexit
14: goto 22
17: astore_2
18: aload_1
19: monitorexit
20: aload_2
21: athrow
22: return
Exception table:
from to target type
4 14 17 any
17 20 17 any
LineNumberTable:
line 25: 0
line 26: 4
line 27: 12
line 28: 22
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 17
locals = [ class com/fonxian/entity/LockDemo, class java/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 /* chop */
offset_delta = 4
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: iconst_0
1: putstatic #5 // Field a:I
4: return
LineNumberTable:
line 8: 0
}
SourceFile: "LockDemo.java"

同步代码块:使用monitorenter和monitorexit指令实现,通过监听器对象去获得锁释放锁

同步方法、静态同步方法:使用修饰符ACC_SYNCHRONIZED实现。

三、锁的形式

JDK1.6前に、唯一の伝統的なロック機構を同期。
偏ったロックロックと軽量:JDK1.6には、ロックの二つの新しいタイプを導入しました。目的には、マルチスレッドの競争、あるいは全く競争例、伝統的なロックによる性能上の問題が存在しない、導入を解決することです。

、何のロック状態を状態、ロック状態軽量、重量級のロック状態をロックする傾向がある:4つの状態がロックしていません。ロックダウングレードではない、アップグレードすることができます。

図1に示すように、オブジェクトヘッド

メカニズムのロックを解除するには、まずオブジェクトヘッダを理解する必要があります。

マークWordのデフォルトのストレージオブジェクトのハッシュコード、年齢や世代ロックフラグのJavaオブジェクトヘッド。

次のようにJavaオブジェクトヘッダ構造を格納することです

ロック状態 25bit 4ビット それはバイアスロックであるかどうかを1ビット 2ビットのロックフラグ
ロックフリー状態 hashCodeオブジェクト 対象の世代の年齢 0 01

状態変化のマーク・ワード

ロック状態 30bit 2ビット
軽量ロック スタックポインタのレコードロックをポインティング ロックフラグ00
ヘビーロック ポインタのポインティングミューテックス ロックフラグ10
ロック状態 23bit 3ビット 3ビット 1ビット 2ビット
バイアスされたロック スレッドID 時代 世代年齢オブジェクト 1 01

図2に示すように、バイアスされたロック

ほとんどの場合、何もロックマルチスレッドの競争、そして同じスレッド数回で得られた合計はありませんので。ロックを獲得するためのコストを下げるために導入されます。

3、軽量ロック

参考資料

1、JDK8 HotSpot仮想マシンソース

オリジナル:ビッグボックス  のJavaロックオン


おすすめ

転載: www.cnblogs.com/chinatrump/p/11614930.html