• 类锁与对象锁的区别

    • 类锁所有对象一把锁
    • 对象锁一个对象一把锁,多个对象多把锁
  • 同步是对同一把锁而言的,同步这个概念是在多个线程争夺同一把锁的时候才能实现的,如果多个线程争夺不同的锁,那多个线程是不能同步的。

    • 两个线程一个取对象锁,一个取类锁,则不能同步
    • 两个线程一个取a对象锁,一个取b对象锁,则不能同步
  • synchronized实现同步的原因在于,保证了拿到锁的线程一定可以一次性把他调用的方法或代码块执行完。

  • synchronized用于方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class B {
// 修饰静态方法,或者修饰普通方法
synchronized public static void mB(String value) throws InterruptedException {
for(int i = 0; i < 1000; ++i) {
System.out.println(value);
}
}

synchronized public void mC(String value) throws InterruptedException {
for(int i = 0; i < 1000; ++i) {
System.out.println(value);
}
}
}
  • synchronized用于代码块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class A {
public static void test() {
// 对类进行同步
synchronized(A.class) {
System.out.println("smlz");
}
}

public void test2() {
// 对当前对象进行同步
synchronized(this) {
System.out.println("smlz");
}
}
}
  • 类锁

    类锁,用来锁类的,使持有者可以同步调用静态方法。当synchronized指定修饰静态方法或者class的时候,拿到的就是类锁。类锁是所有对象共抢一把锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class B {
synchronized public static void mB(String value) throws InterruptedException {
for(int i = 0; i < 1000; ++i) {
System.out.print(value);
}
}

public void mC(String value) {
synchronized(B.class) {
for(int i = 0; i < 1000; ++i){
System.out.print(value);
}
}
}
}
  • 对象锁

    用来锁对象,每个对象各有一把。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class C {
synchronized public void mB(String value) throws InterruptedException {
for(int i = 0; i < 1000; ++i) {
System.out.print(value);
}
}

public void mC(String value) {
synchronized(this) {
for(int i = 0; i < 1000; ++i) {
System.out.print(value);
}
}
}
}
  • 测试案例

    1、两个线程调用同一个对象b的mB方法和mC方法,最终1000次1和1000次2的结果是分开的,即调用对象锁实现了同步

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
public class B {

synchronized public void mB(String value) throws InterruptedException {
for(int i = 0; i < 1000; ++i) {
System.out.println(value);
}
}

public void mC(String value) throws InterruptedException {
synchronized(this) {
for(int i = 0; i < 1000; ++i) {
System.out.println(value);
}
}
}
}


public class ApplicationDemo {
public static void main(String[] args) {
B b = new B();

Thread thread_1 = new Thread(new Runnable() {
@Override
public void run() {
try {
b.mB("1");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
});

Thread thread_2 = new Thread(new Runnable() {
@Override
public void run() {
try {
b.mC("2");
} catch(InterrutedException e) {
e.printStackTrace();
}
}
});

thread_1.start();
thread_2.start();
}
}

2、使用类锁进行测试,同样1和2是分开的

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
public class B {
synchronized public static void mB(String value) throws InterruptedException {
for(int i = 0; i < 1000; ++i) {
System.out.println(value);
}
}

public static void mC(String value) throws InterruptedException {
synchronized(B.class) {
for(int i = 0; i < 1000; ++i) {
System.out.println(value);
}
}
}
}


public class ApplicationDemo {
public static void main(String[] args) {

Thread thread_1 = new Thread(new Runnable() {
@Override
public void run() {
try {
B.mB("1");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
});

Thread thread_2 = new Thread(new Runnable() {
@Override
public void run() {
try {
B.mC("2");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
});

thread_1.start();
thread_2.start();
}
}

3、但如果类锁和对象锁同时存在,则无法保证同步,即1和2将交替打出

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
public class B {
synchronized public static void mB(String value) throws InterruptedException {
for(int i = 0; i < 1000; ++i) {
System.out.println(value);
}
}

public void mC(String value) throws InterruptedException {
synchronized(this) {
for(int i = 0; i < 1000; ++i) {
System.out.println(value);
}
}
}
}


public class ApplicationDemo {
public static void main(String[] args) {

Thread thread_1 = new Thread(new Runnable() {
@Override
public void run() {
try {
B.mB("1");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
});

B b = new B();
Thread thread_2 = new Thread(new Runnable() {
@Override
public void run() {
try {
b.mC("2");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
});

thread_1.start();
thread_2.start();
}
}

(仅个人整理,非原创)

(感谢大佬原创,原文链接