java并发synchronized 锁的膨胀过程(锁的升级过程)深入剖析(2)

接下来我们分析两个批量偏向撤销的相关案例(禁止偏向锁延迟的情况下:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0):

案例一:

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

public class TestDemo {

}

  

public class DemoExample6 {

    public static void main(String[] args) throws InterruptedException {

        test2();

    }

   

    /**

     * 证明偏量偏向撤销

     * @throws InterruptedException

     */

    public  static  void test2() throws InterruptedException {

        List<TestDemo> list = new ArrayList<TestDemo>();

        for (int i = 0; i < 100; i++) {

            list.add(new TestDemo());

        }

        Thread t1 = new Thread(()->{

            System.out.println("加锁前 get(0) 应该是无锁可偏向 "+ClassLayout.parseInstance(list.get(0)).toPrintable());

            for (TestDemo a:list  ) {

                synchronized (a){

                    System.out.print("加锁 >");

                }

            }

            System.out.println();

            System.out.println("加锁后 get(0) 应该是偏向锁"+ClassLayout.parseInstance(list.get(0)).toPrintable());

            try {

                TimeUnit.SECONDS.sleep(1000);//这里不让线程死,防止线程ID复用

            catch (InterruptedException e) {

                e.printStackTrace();

            }

        });

        t1.start();

        TimeUnit.SECONDS.sleep(5);

        Thread t2 = new Thread(()->{

            for (int i = 0; i < 100; i++) {

                TestDemo a = list.get(i);

                synchronized (a){

                    System.out.println(Thread.currentThread().getId()+"加锁 >");

                }

                try {

                    TimeUnit.MILLISECONDS.sleep(100);

                catch (InterruptedException e) {

                    e.printStackTrace();

                }

                if (i==9){//这里刚好是第19个上锁的(同样是第19个偏向锁升级的)

                    System.out.println();

                    System.out.println("加锁后 get(9) 应该是无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable());

                }

                if (i==10){//这里刚好是第21个上锁的

                    System.out.println();

                    System.out.println("加锁后 get(10) 应该是偏向锁 偏向t2 "+ClassLayout.parseInstance(list.get(i)).toPrintable());

                }

                if (i==50){//50开始升级为轻量级锁(同样是第21个偏向锁升级的)

                    System.out.println();

                    System.out.println("加锁后 get(50) 无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable());

                }

                if (i==59){//60(同样是第39个偏向锁升级的)

                    System.out.println();

                    System.out.println("加锁后 get(59) 无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable());

                }

                if (i==69){//69(同样是第59个偏向锁升级的)

                    System.out.println();

                    System.out.println("加锁后 get(69) 无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(i)).toPrintable());

                    TestDemo a1 = new TestDemo();

                    synchronized (a1){

                        System.out.println("偏向撤销发生后的该类新建的对象都不会再偏向任何线程 "+ClassLayout.parseInstance(a1).toPrintable());

                    }

                }

            }

        });

   

        Thread t3 = new Thread(()->{

            for (int i = 99; i >= 0; i--) {

                TestDemo a = list.get(i);

                synchronized (a){

                    System.out.println(Thread.currentThread().getId()+"加锁 >");

                }

                try {

                    TimeUnit.MILLISECONDS.sleep(100);

                catch (InterruptedException e) {

                    e.printStackTrace();

                }

                /**

                 * 重点:重偏向撤销

                 */

                if (i==40){//40升级为轻量级锁(同样是第40个偏向锁升级的,这时候发生偏向撤销)

                    System.out.println();

                    System.out.println("加锁后 get("+i+") 应该是无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(0)).toPrintable());

                    TestDemo a1 = new TestDemo();

                    synchronized (a1){

                        System.out.println("偏向撤销发生后的该类新建的对象都不会再偏向任何线程 "+ClassLayout.parseInstance(a1).toPrintable());

                    }

                }

                if (i==30){//39升级为轻量级锁(同样是第42个偏向锁升级的)

                    System.out.println();

                    System.out.println("加锁后 get("+i+") 应该是无锁(轻量级锁释放) "+ClassLayout.parseInstance(list.get(0)).toPrintable());

                    TestDemo a1 = new TestDemo();

                    synchronized (a1){

                        System.out.println("偏向撤销发生后的该类新建的对象都不会再偏向任何线程 "+ClassLayout.parseInstance(a1).toPrintable());

                    }

                }

            }

        });

        t2.start();

        TimeUnit.MILLISECONDS.sleep(50);

        t3.start();

    }

}  

 

运行结果(截取部分):

加锁前 get(0) 应该是无锁可偏向 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >加锁 >

 

加锁后 get(0) 应该是偏向锁com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 e0 84 08 (00000101 11100000 10000100 00001000) (142925829)

      4     4        (object header)                           b1 7f 00 00 (10110001 01111111 00000000 00000000) (32689)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

加锁后 get(9) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

15加锁 >

 

 

加锁后 get(90) 应该是偏向锁 偏向t3com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 89 01 0c (00000101 10001001 00000001 00001100) (201427205)

      4     4        (object header)                           b1 7f 00 00 (10110001 01111111 00000000 00000000) (32689)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

加锁后 get(10) 应该是偏向锁 偏向t2 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 b1 0a 08 (00000101 10110001 00001010 00001000) (134918405)

      4     4        (object header)                           b1 7f 00 00 (10110001 01111111 00000000 00000000) (32689)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

15加锁 >

 

 

加锁后 get(89) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

加锁后 get(50) 无锁(轻量级锁释放) com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

15加锁 >

  

加锁后 get(49) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

加锁后 get(59) 无锁(轻量级锁释放) com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

  

15加锁 > 

 

加锁后 get(40) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

  

偏向撤销发生后的该类新建的对象都不会再偏向任何线程 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           48 18 a6 09 (01001000 00011000 10100110 00001001) (161880136)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

加锁后 get(69) 无锁(轻量级锁释放) com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

  

偏向撤销发生后的该类新建的对象都不会再偏向任何线程 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           50 e8 95 09 (01010000 11101000 10010101 00001001) (160819280)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

  

15加锁 >

 

加锁后 get(30) 应该是无锁(轻量级锁释放) com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

  

偏向撤销发生后的该类新建的对象都不会再偏向任何线程 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           48 18 a6 09 (01001000 00011000 10100110 00001001) (161880136)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

案例二:

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

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

public class TestDemo {

}

public class DemoExample8 {

    public static void main(String[] args) throws Exception {

        List<TestDemo> list = new ArrayList<>();

        List<TestDemo> list2 = new ArrayList<>();

        List<TestDemo> list3 = new ArrayList<>();

        for (int i = 0; i < 100; i++) {

            list.add(new TestDemo());

            list2.add(new TestDemo());

            list3.add(new TestDemo());

        }

        //偏向锁

        System.out.println("初始状态" 10 + ClassLayout.parseClass(TestDemo.class).toPrintable());

   

        Thread t1 = new Thread() {

            String name = "1";

            public void run() {

                System.out.printf(name);

                for (TestDemo a : list) {

                    synchronized (a) {

                        if (a == list.get(10)) {

                            //偏向锁

                            System.out.println("t1 预期是偏向锁" 10 + ClassLayout.parseInstance(a).toPrintable());

                        }

                    }

                }

                try {

                    Thread.sleep(100000);

                catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        };

        t1.start();

        Thread.sleep(5000);

        //偏向锁

        System.out.println("main 预期是偏向锁" 10 + ClassLayout.parseInstance(list.get(10)).toPrintable());

        Thread t2 = new Thread() {

            String name = "2";

            public void run() {

                System.out.printf(name);

                for (int i = 0; i < 100; i++) {

                    TestDemo a = list.get(i);

                    synchronized (a) {

                        if (a == list.get(10)) {

                            System.out.println("t2 i=10 get(1)预期是无锁" + ClassLayout.parseInstance(list.get(1)).toPrintable());//偏向锁

                            System.out.println("t2 i=10 get(10) 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                        }

                        if (a == list.get(19)) {

                            System.out.println("t2  i=19  get(10)预期是无锁" 10 + ClassLayout.parseInstance(list.get(10)).toPrintable());//偏向锁

                            System.out.println("t2  i=19  get(19) 满足重偏向条件20 预期偏向锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                            System.out.println("类的对象累计撤销达到20");

                        

                    }

                }

                try {

                    Thread.sleep(100000);

                catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        };

        t2.start();

        Thread.sleep(5000);

  

        Thread t3 = new Thread() {

            String name = "3";

            public void run() {

                System.out.printf(name);

                for (TestDemo a : list2) {

                    synchronized (a) {

                        if (a == list2.get(10)) {

                            System.out.println("t3 预期是偏向锁" 10 + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                        }

                    }

                }

                try {

                    Thread.sleep(100000);

                catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        };

        t3.start();

        Thread.sleep(5000);

  

        Thread t4 = new Thread() {

            String name = "4";

            public void run() {

                System.out.printf(name);

                for (int i = 0; i < 100; i++) {

                    TestDemo a = list2.get(i);

                    synchronized (a) {

                        if (a == list2.get(10)) {

                            System.out.println("t4 i=10 get(1)预期是无锁" + ClassLayout.parseInstance(list2.get(1)).toPrintable());//偏向锁

                            System.out.println("t4 i=10 get(10) 当前不满足重偏向条件 20 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                        }

                        if (a == list2.get(19)) {

                            System.out.println("t4  i=19  get(10)预期是无锁" 10 + ClassLayout.parseInstance(list2.get(10)).toPrintable());//偏向锁

                            System.out.println("t4 i=19 get(19) 当前满足重偏向条件 20 但A类的对象累计撤销达到40 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                            System.out.println("类的对象累计撤销达到40");

                        }

                        if (a == list2.get(20)) {

                            System.out.println("t4 i=20 get(20) 当前满足重偏向条件 20 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                        }

                    }

                }

            }

        };

        t4.start();

        Thread.sleep(5000);

        System.out.println("main 预期是偏向锁" 10 + ClassLayout.parseInstance(list3.get(0)).toPrintable());//偏向锁

        Thread t5 = new Thread() {

            String name = "5";

            public void run() {

                System.out.printf(name);

                for (TestDemo a : list3) {

                    synchronized (a) {

                        if (a == list3.get(10)) {

                            System.out.println("t5 预期是轻量级锁,类的对象累计撤销达到40 不可以用偏向锁了" 10 + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                        }

                    }

                }

                try {

                    Thread.sleep(100000);

                catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        };

        t5.start();

        Thread.sleep(5000);

        System.out.println("main 预期是偏向锁" 10 + ClassLayout.parseInstance(list.get(10)).toPrintable());//偏向锁

  

        Thread t6 = new Thread() {

            String name = "6";

            public void run() {

                System.out.printf(name);

                for (int i = 0; i < 100; i++) {

                    TestDemo a = list3.get(i);

                    synchronized (a) {

                        if (a == list3.get(10)) {

                            System.out.println("t6 i=10 get(1)预期是无锁" + ClassLayout.parseInstance(list3.get(1)).toPrintable());//偏向锁

                            System.out.println("t6 i=10 get(10) 预期轻量级锁 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                        }

                        if (a == list3.get(19)) {

                            System.out.println("t6  i=19  get(10)预期是无锁" 10 + ClassLayout.parseInstance(list3.get(10)).toPrintable());//偏向锁

                            System.out.println("t6  i=19  get(19) 满足重偏向条件20 但类的对象累计撤销达到40 不可以用偏向锁了 " + i + ClassLayout.parseInstance(a).toPrintable());//偏向锁

                        }

                    }

                }

  

                try {

                    Thread.sleep(100000);

                catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        };

        t6.start();

        Thread.sleep(5000);

  

        System.out.println("由于撤销锁次数达到默认的 BiasedLockingBulkRevokeThreshold=40 这里实例化的对象 是无锁状态" + ClassLayout.parseInstance(new TestDemo()).toPrintable());//偏向锁

     System.out.println("撤销偏向后状态" 10 + ClassLayout.parseInstance(new TestDemo()).toPrintable());//偏向锁

  }

}

   

运行结果:

初始状态10 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0    12        (object header)                           N/A

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

1t1 预期是偏向锁10 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 e0 86 8e (00000101 11100000 10000110 10001110) (-1903763451)

      4     4        (object header)                           ec 7f 00 00 (11101100 01111111 00000000 00000000) (32748)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

main 预期是偏向锁10 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 e0 86 8e (00000101 11100000 10000110 10001110) (-1903763451)

      4     4        (object header)                           ec 7f 00 00 (11101100 01111111 00000000 00000000) (32748)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

2t2 i=10 get(1)预期是无锁com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t2 i=10 get(10) 预期轻量级锁 10 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           08 99 7a 03 (00001000 10011001 01111010 00000011) (58366216)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t2  i=19  get(10)预期是无锁10 com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t2  i=19  get(19) 满足重偏向条件20 预期偏向锁 19com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 09 90 91 (00000101 00001001 10010000 10010001) (-1852831483)

      4     4        (object header)                           ec 7f 00 00 (11101100 01111111 00000000 00000000) (32748)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

类的对象累计撤销达到20

3t3 预期是偏向锁10com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 09 89 90 (00000101 00001001 10001001 10010000) (-1870067451)

      4     4        (object header)                           ec 7f 00 00 (11101100 01111111 00000000 00000000) (32748)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

4t4 i=10 get(1)预期是无锁com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t4 i=10 get(10) 当前不满足重偏向条件 20 预期轻量级锁 10com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           08 f9 9a 03 (00001000 11111001 10011010 00000011) (60487944)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t4  i=19  get(10)预期是无锁10com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t4 i=19 get(19) 当前满足重偏向条件 20 但A类的对象累计撤销达到40 预期轻量级锁 19com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           08 f9 9a 03 (00001000 11111001 10011010 00000011) (60487944)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

类的对象累计撤销达到40

t4 i=20 get(20) 当前满足重偏向条件 20 预期轻量级锁 20com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           08 f9 9a 03 (00001000 11111001 10011010 00000011) (60487944)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

main 预期是偏向锁10com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

5t5 预期是轻量级锁,A类的对象累计撤销达到40 不可以用偏向锁了10com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           08 f9 9a 03 (00001000 11111001 10011010 00000011) (60487944)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

main 预期是偏向锁10com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

6t6 i=10 get(1)预期是无锁com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t6 i=10 get(10) 预期轻量级锁 10com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           08 29 ab 03 (00001000 00101001 10101011 00000011) (61548808)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t6  i=19  get(10)预期是无锁10com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t6  i=19  get(19) 满足重偏向条件20 但A类的对象累计撤销达到40 不可以用偏向锁了 19com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           08 29 ab 03 (00001000 00101001 10101011 00000011) (61548808)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

由于类撤销锁次数达到默认的 BiasedLockingBulkRevokeThreshold=40 这里实例化的对象 是无锁状态com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)

      8     4        (object header)                           bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

撤销偏向后状态10com.boke.TestDemo object internals:
OFFSET SIZE TYPE DESCRIPTION                     VALUE
  0    4        (object header)                01 00 00 00 (00000001 00000000 00000000 00000000) (1)
  4    4        (object header)               00 00 00 00 (00000000 00000000 00000000 00000000) (0)
  8    4        (object header)                bf c3 00 f8 (10111111 11000011 00000000 11111000) (-134167617)
  12   4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

以上案例证实了偏向锁的批量重偏向和批量撤销,接下来我们讲解轻量级锁;

 


 

轻量级锁:

 

  • 当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。
  • 在代码进入同步块的时候,如果同步对象锁状态为无锁状态(锁标志位为“01”状态,是否为偏向锁为“0”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,然后拷贝对象头中的Mark Word复制到锁记录中。
  • 拷贝成功后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针,并将Lock Record里的owner指针指向对象的Mark Word。
  • 如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位设置为“00”,表示此对象处于轻量级锁定状态。
  • 如果轻量级锁的更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行,否则说明多个线程竞争锁。
  • 若当前只有一个等待线程,则该线程通过自旋进行等待。但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁升级为重量级锁。
  • 多个线程在不同的时间段请求同一把锁,也就是说没有锁竞争。针对这种情形,Java 虚拟机采用了轻量级锁,来避免重量级锁的阻塞以及唤醒
  • 在没有锁竞争的前提下,减少传统锁使用OS互斥量产生的性能损耗
  • 在竞争激烈时,轻量级锁会多做很多额外操作,导致性能下降
  • 可以认为两个线程交替执行的情况下请求同一把锁

 

分析一个由偏向锁膨胀成轻量级锁的案例:

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

public class TestDemo {

}

public class DemoExample9 {

    public static void main(String[] args) throws Exception {

        TestDemo testDemo = new TestDemo();

  

        //子线程

        Thread t1 = new Thread(){

            @Override

            public void run() {

                synchronized (testDemo){

                    System.out.println("t1 lock ing");

                    System.out.println(ClassLayout.parseInstance(testDemo).toPrintable());

                }

            }

        };

         

        t1.join();

  

        //主线程

        synchronized (testDemo){

            System.out.println("main lock ing");

            System.out.println(ClassLayout.parseInstance(testDemo).toPrintable());

        }

  

    }

}

  

运行结果(两个线程交替执行的情况下):

main lock ing

com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           e8 48 95 09 (11101000 01001000 10010101 00001001) (160778472)

      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)

      8     4        (object header)                           a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 


 

重量级锁:

 

  • 多个线程竞争同一个锁的时候,虚拟机会阻塞加锁失败的线程,并且在目标锁被释放的时候,唤醒这些线程;
  • Java 线程的阻塞以及唤醒,都是依靠操作系统来完成的:os pthread_mutex_lock() ;
  • 升级为重量级锁时,锁标志的状态值变为“10”,此时Mark Word中存储的是指向重量级锁的指针,此时等待锁的线程都会进入阻塞状态

  

分析一个由轻量级锁膨胀成重量级锁的案例:

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

public class TestDemo {

}

public class DemoExample9 {

    public static void main(String[] args) throws Exception {

        TestDemo testDemo = new TestDemo();

  

  

        Thread t1 = new Thread(){

            @Override

            public void run() {

                synchronized (testDemo){

                    System.out.println("t1 lock ing");

                    System.out.println(ClassLayout.parseInstance(testDemo).toPrintable());

                }

            }

        };

  

        t1.start();

  

        synchronized (testDemo){

            System.out.println("main lock ing");

            System.out.println(ClassLayout.parseInstance(testDemo).toPrintable());

        }

    }

}

 

 运行结果:

main lock ing

com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           5a ad 00 b0 (01011010 10101101 00000000 10110000) (-1342132902)

      4     4        (object header)                           cf 7f 00 00 (11001111 01111111 00000000 00000000) (32719)

      8     4        (object header)                           a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160)

     12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

t1 lock ing

com.boke.TestDemo object internals:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE

      0     4        (object header)                           5a ad 00 b0 (01011010 10101101 00000000 10110000) (-1342132902)

      4     4        (object header)                           cf 7f 00 00 (11001111 01111111 00000000 00000000) (32719)

      8     4        (object header)                           a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160)

     12     4        (loss due to the next object alignment)


 

我们再来说一下Java 虚拟机是怎么区分轻量级锁和重量级锁的:

  • 当进行加锁操作时,Java 虚拟机会判断是否已经是重量级锁。如果不是,它会在当前线程的当前栈桢中划出一块空间,作为该锁的锁记录,并且将锁对象的标记字段复制到该锁记录中。

  • 然后,Java 虚拟机会尝试用 CAS(compare-and-swap)操作替换锁对象的标记字段。这里解释一下,CAS 是一个原子操作,它会比较目标地址的值是否和期望值相等,如果相等,则替换为一个新的值。

  • 假设当前锁对象的标记字段为 X…XYZ,Java 虚拟机会比较该字段是否为 X…X01。如果是,则替换为刚才分配的锁记录的地址。由于内存对齐的缘故,它的最后两位为 00。此时,该线程已成功获得这把锁,可以继续执行了。

  • 如果不是 X…X01,那么有两种可能。第一,该线程重复获取同一把锁。此时,Java 虚拟机会将锁记录清零,以代表该锁被重复获取。第二,其他线程持有该锁。此时,Java 虚拟机会将这把锁膨胀为重量级锁,并且阻塞当前线程。

  • 当进行解锁操作时,如果当前锁记录(你可以将一个线程的所有锁记录想象成一个栈结构,每次加锁压入一条锁记录,解锁弹出一条锁记录,当前锁记录指的便是栈顶的锁记录)的值为 0,则代表重复进入同一把锁,直接返回即可。

  • 否则,Java 虚拟机会尝试用 CAS 操作,比较锁对象的标记字段的值是否为当前锁记录的地址。如果是,则替换为锁记录中的值,也就是锁对象原本的标记字段。此时,该线程已经成

  • 功释放这把锁。

  • 如果不是,则意味着这把锁已经被膨胀为重量级锁。此时,Java 虚拟机会进入重量级锁的释放过程,唤醒因竞争该锁而被阻塞了的线程

 


 

到此为止本篇就讲完了锁的膨胀过程

 

 

总结一下

  1. 偏向锁只会在第一次请求时采用 CAS 操作,在锁对象的标记字段中记录下当前线程的地址。在之后的运行过程中,持有该偏向锁的线程的加锁操作将直接返回。它针对的是锁仅会被同一线程持有的情况。

  2. 轻量级锁采用 CAS 操作,将锁对象的标记字段替换为一个指针,指向当前线程栈上的一块空间,存储着锁对象原本的标记字段。它针对的是多个线程在不同时间段申请同一把锁的情况。

  3. 重量级锁会阻塞、唤醒请求加锁的线程。它针对的是多个线程同时竞争同一把锁的情况。Java 虚拟机采取了自适应自旋,来避免线程在面对非常小的 synchronized 代码块时,仍会被阻塞、唤醒的情况。

 


 

 

说完了锁的膨胀过程,那么会不会有锁的降级呢?

 

我在hotspot源码中找到了这样的注释:

// We create a list of in-use monitors for each thread.//// deflate_thread_local_monitors() scans a single thread's in-use list, while// deflate_idle_monitors() scans only a global list of in-use monitors which// is populated only as a thread dies (see omFlush()).//// These operations are called at all safepoints, immediately after mutators// are stopped, but before any objects have moved. Collectively they traverse// the population of in-use monitors, deflating where possible. The scavenged// monitors are returned to the monitor free list.//// Beware that we scavenge at *every* stop-the-world point. Having a large// number of monitors in-use could negatively impact performance. We also want// to minimize the total # of monitors in circulation, as they incur a small// footprint penalty.//// Perversely, the heap size -- and thus the STW safepoint rate --// typically drives the scavenge rate.  Large heaps can mean infrequent GC,// which in turn can mean large(r) numbers of objectmonitors in circulation.// This is an unfortunate aspect of this design.//大概意思是:锁降级确实是会发生的,当 JVM 进入安全点(SafePoint)的时候,会检查是否有闲置的 Monitor,然后试图进行降级有兴趣的大佬可以在https://hg.openjdk.java.net/jdk/jdk/file/896e80158d35/src/hotspot/share/runtime/synchronizer.cpp链接中:研究一下deflate_idle_monitors是分析锁降级逻辑的入口,这部分行为还在进行持续改进,因为其逻辑是在安全点内运行,处理不当可能拖长 JVM 停顿(STW,stop-the-world)的时间。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/386485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

连续四年百度Android岗必问面试题!Android校招面试指南

前言 刚从阿里面试回来&#xff0c;想和大家分享一些我的面试经验&#xff0c;以及面试题目。 这篇文章将会更加聚焦在面试前需要看哪些资料&#xff0c;一些面试技巧以及一些这次的面试考题。 面试经历 7月确定想走后开始看各种面经&#xff0c;复习基础知识&#xff0c;月…

透彻解析!字节跳动Android实习面试凉凉经,年薪超过80万!

什么是Kotlin? Kotlin&#xff0c;如前面所说&#xff0c;它是JetBrains开发的基于JVM的语言。JetBrains因为创造了一个强大的Java开发IDE被大家所熟知。Android Studio&#xff0c;官方的Android IDE&#xff0c;就是基于Intellij&#xff0c;作为一个该平台的插件。 Kotli…

synchronized 底层如何实现?什么是锁升级、降级?

synchronized 底层如何实现&#xff1f;什么是锁升级、降级&#xff1f; synchronized 代码块是由一对 monitorenter/monitorexit 指令实现的&#xff0c;Monitor 对象是同步的基本实现单元。 https://docs.oracle.com/javase/specs/jls/se10/html/jls-8.html#d5e13622 在Jav…

Spring主要用到两种设计模式

Spring主要用到两种设计模式 1、工厂模式 Spring容器就是实例化和管理全部Bean的工厂。 工厂模式可以将Java对象的调用者从被调用者的实现逻辑中分离出来。 调用者只关心被调用者必须满足的某种规则&#xff0c;这里的规则我们可以看做是接口&#xff0c;而不必关心实例的具体实…

意外收获字节跳动内部资料,已开源

前言 每年的3、4月份是各大企业为明年拓展业务大量吸纳人才的关键时期&#xff0c;招聘需求集中、空缺岗位多&#xff0c;用人单位也习惯在初秋进行大规模招聘。 金九银十&#xff0c;招聘旺季&#xff0c;也是一个求职旺季。 不打无准备的仗&#xff0c;在这种关键时期&…

成功跳槽百度工资从15K涨到28K,威力加强版

前言 看到一篇文章中提到“最近几年国内的初级Android程序员已经很多了&#xff0c;但是中高级的Android技术人才仍然稀缺“&#xff0c;这的确不假&#xff0c;从我在百度所进行的一些面试来看&#xff0c;找一个适合的高级Android工程师的确不容易&#xff0c;一般需要进行大…

Redis下载及安装(windows版)

下载地址 1、Github下载地址&#xff1a;https://github.com/MicrosoftArchive/redis/releases 2、百度网盘下载地址 https://pan.baidu.com/s/1z1_OdNVbtgyEjiktqgB83g 密码&#xff1a;kdfq 安装过程 1.首先先把下载的压缩包解压到一个文件夹中 2.打开cmd指令窗口 3.输入你刚…

成功跳槽百度工资从15K涨到28K,跳槽薪资翻倍

前言 这篇文章主要是分享今年上半年的面试心得&#xff0c;现已就职于某大厂有三个月了&#xff0c;近期有很多公司均已启动秋招&#xff0c;也祝大家在 2020 的下半年面试顺利&#xff0c;获得理想的offer&#xff01; 之前找工作的那段时间感想颇多&#xff0c;总结一点面试…

分布式锁RedLock的java实现Redisson

1. 概述Redisson是一个在Redis的基础上实现的Java驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;。它不仅提供了一系列的分布式的Java常用对象&#xff0c;还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue,…

我三年开发经验,从字节跳动抖音离职后,看看这篇文章吧!

最新BAT大厂面试者整理的Android面试题目&#xff01; 近期根据网友分享大厂面试题目&#xff0c;今天我将网友面试的BAT等大厂Android面试题目整理出来&#xff0c;希望能够帮助大家&#xff01; 珍藏版&#xff08;1&#xff09;——高级 UI 晋升 第一节、触摸事件分发机制…

arthas命令redefine实现Java热更新

Arthas非常重要的命令redefine&#xff0c;主要作用是加载外部的.class文件&#xff0c;用来替换JVM已经加载的类&#xff0c;总结起来就是实现了Java的热更新。 redefine在一下几种情况中会失败&#xff1a;1、增加了field&#xff1b;2、增加了method&#xff1b;3、替换正在…

我了解到的面试的一些小内幕!附面试题答案

背景 首先我是个菜鸡&#xff0c;工资也低的一笔。 刚毕业时候在一家国企上班干 app 开发&#xff0c;干了快两年的时候&#xff0c;跳槽到了一家伪大厂干安全。投了不少简历都没有回音&#xff0c;只有这加伪大厂要我就来了。当时说好了会接触一些底层的东西&#xff0c;然而…

学习单调队列小结

因为一直在听身边的人说什么单调队列/斜率优化dp/背包&#xff0c;(ps:我也不清楚这样称呼对不对&#xff0c;因为我真心是没见过这些东西)我都觉得那是神一样的东西。终于抽出时间学了一下。 昨天在朋友一本书里面看到一句话&#xff0c;这里先跟大家分享一下&#xff1a; 没有…

我们究竟还要学习哪些Android知识?完整版开放下载

前言 移动研发火热不停&#xff0c;越来越多人开始学习 android 开发。但很多人感觉入门容易成长很难&#xff0c;对未来比较迷茫&#xff0c;不知道自己技能该怎么提升&#xff0c;到达下一阶段需要补充哪些内容。市面上也多是谈论知识图谱&#xff0c;缺少体系和成长节奏感&a…

ELK7.8.1的Docker搭建过程

在linux下首先在目录准备文件 首先说明&#xff0c;我的电脑宿主机的IP是192.168.1.5 为es准备文件 mkdir -p /opt/elk7/es cd /opt/elk7/es #创建对应的文件夹 数据 / 日志 / 配置 mkdir conf data logs #授权 chmod 777 -R conf data logs然后进入到/opt/elk7/es/conf下 …

如何使用git创建项目,创建分支

git config -global user.name "Your name" git config -global user.email "youexample.com" 建立一个存放工程的文件夹 git init命令用于初始化当前所在目录的这个项目 会创建一个隐藏文件 .git 创建 main.c 文件 创建 .gitignore文件&#xff0c;忽略…

我们究竟还要学习哪些Android知识?附赠课程+题库

2021新的一年&#xff0c;开启新的征程&#xff0c;回顾2020&#xff0c;真是太“南”了。 从年初各大厂裁员&#xff0c;竟然成为一件理所应当的事情&#xff0c;到四月份 GitHub 上“996.ICU” 引起了大家的共鸣。即使我们兢兢业业“996”&#xff0c;但依旧难以抵御 35 岁时…

WINDOWS上KAFKA运行环境安装

WINDOWS上KAFKA运行环境安装 1. 安装JDK 1.1 安装文件&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/index.html 下载JDK 1.2 安装完成后需要添加以下的环境变量&#xff08;右键点击“我的电脑” -> "高级系统设置" -> "环境变…

架构师成长之路-个人学习经验分享(公司研发峰会演讲ppt)

前天在公司分享了一些学习经验,园子中感兴趣可以看看。建议大家使用pptPlex来看这个片子。 首先从我在成长中不同阶段的工作和体会来谈不同阶段的学习内容谈起&#xff0c;为了做好这些必修课&#xff0c;我会对知识&#xff0b;实践&#xff0b;思考&#xff0b;心态&#xff…

我凭什么拿到了阿里、腾讯、今日头条3家大厂offer?这原因我服了

前言 从毕业到现在面试也就那么几家公司&#xff0c;单前几次都比较顺利&#xff0c;在面到第三家时都给到了我offer&#xff01;前面两次找工作&#xff0c;没考虑到以后需要什么&#xff0c;自己的对未来的规划是什么&#xff0c;只要有份工作&#xff0c;工资符合自己的要求…