在Java中,synchronized 是用来表示同步的,我们可以synchronized 来修饰一个方法。也可以synchronized 来修饰方法里面的一个语句块。
修饰实例方法:
1. public synchronized void normalMethod() throws InterruptedException {
2. for (int i = 0; i < 10; i++) {
3. 1000);
4. "normalMethod:" + i);
5. }
6. }
修饰类方法(static 方法):
1. public static synchronized void staticMethod() throws InterruptedException {
2. for (int i = 0; i < 10; i++) {
3. 500);
4. "staticMethod:" + i);
5. }
6. }
修饰方法里面语句块:
1. public static void staticMethod() throws InterruptedException {
2. synchronized (locks) {
3. for (int i = 0; i < 10; i++) {
4. 1000);
5. "staticMethod:" + i);
6. }
7. }
8. }
注意:这里不能用synchronized修饰方法外面的语句块(我把他叫做类语句块),虽然我们可以在方法外面定义语句块,这样做会遇到编译错误,这里涉及到了Java里面的对象初始化的部分知识。大概的原因就是synchronized锁住的是对象,当初始化对象的时候,JVM在对象初始化完成之前会调用方法外面的语句块,这个时候对象还不存在,所以就不存在锁了。
那么,在static方法和非static方法前面加synchronized到底有什么不同呢?
static的方法属于类方法,它属于这个Class(注意:这里的Class不是指Class的某个具体对象),那么static获取到的锁,就是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。而非static方法获取到的锁,就是当前调用这个方法的对象的锁了。所以,他们之间不会产生互斥。
实例1:
1. package com.bijian.thread;
2.
3. public class SynchronizedTest {
4.
5. public static synchronized void staticMethod() throws InterruptedException {
6. for (int i = 0; i < 10; i++) {
7. 500);
8. "staticMethod:" + i);
9. }
10. }
11.
12. public synchronized void normalMethod() throws InterruptedException {
13. for (int i = 0; i < 10; i++) {
14. 1000);
15. "normalMethod:" + i);
16. }
17. }
18.
19. public static void main(String[] args) {
20. final SynchronizedTest synchronizedTest = new SynchronizedTest();
21. new Thread(new Runnable() {
22. public void run() {
23. try {
24. synchronizedTest.normalMethod();
25. catch (InterruptedException e) {
26. e.printStackTrace();
27. }
28. }
29. "a");
30.
31. new Thread(new Runnable() {
32. public void run() {
33. try {
34. SynchronizedTest.staticMethod();
35. catch (InterruptedException e) {
36. e.printStackTrace();
37. }
38. }
39. "b");
40.
41. thread1.start();
42. thread.start();
43. }
44. }
运行结果:
1. staticMethod:0
2. normalMethod:0
3. staticMethod:1
4. staticMethod:2
5. normalMethod:1
6. staticMethod:3
7. staticMethod:4
8. normalMethod:2
9. staticMethod:5
10. staticMethod:6
11. normalMethod:3
12. staticMethod:7
13. staticMethod:8
14. normalMethod:4
15. staticMethod:9
16. normalMethod:5
17. normalMethod:6
18. normalMethod:7
19. normalMethod:8
20. normalMethod:9
那当我们想让所有这个类下面的对象都同步的时候,也就是让所有这个类下面的对象共用同一把锁的时候,我们如何办呢?
法1:将normalMethod方法也改成static,这样这两个static方法都属于类方法,它们获取到的锁都是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。但这样会影响代码结构和对象的封装性。
修改实例1如下:
1. package com.bijian.thread;
2.
3. public class SynchronizedTest {
4. public static synchronized void staticMethod() throws InterruptedException {
5. for (int i = 0; i < 10; i++) {
6. 500);
7. "staticMethod:" + i);
8. }
9. }
10. public static synchronized void normalMethod() throws InterruptedException {
11. for (int i = 0; i < 10; i++) {
12. 1000);
13. "normalMethod:" + i);
14. }
15. }
16.
17. public static void main(String[] args) {
18. new Thread(new Runnable() {
19. public void run() {
20. try {
21. SynchronizedTest.normalMethod();
22. catch (InterruptedException e) {
23. e.printStackTrace();
24. }
25. }
26. "a");
27.
28. new Thread(new Runnable() {
29. public void run() {
30. try {
31. SynchronizedTest.staticMethod();
32. catch (InterruptedException e) {
33. e.printStackTrace();
34. }
35. }
36. "b");
37.
38. thread1.start();
39. thread.start();
40. }
41. }
运行结果:
1. staticMethod:0
2. staticMethod:1
3. staticMethod:2
4. staticMethod:3
5. staticMethod:4
6. staticMethod:5
7. staticMethod:6
8. staticMethod:7
9. staticMethod:8
10. staticMethod:9
11. normalMethod:0
12. normalMethod:1
13. normalMethod:2
14. normalMethod:3
15. normalMethod:4
16. normalMethod:5
17. normalMethod:6
18. normalMethod:7
19. normalMethod:8
20. normalMethod:9
也许有人说:将实例1的staticMethod方法改成的static去掉也能达到目的。确实可以,因为非static方法获取到的锁,就是当前调用这个方法的对象的锁,而实例1只有一个SynchronizedTest实例,如再创建一个实例,则就有问题了。如下所示:
1. package com.bijian.thread;
2.
3. public class SynchronizedTest {
4.
5. public synchronized void staticMethod() throws InterruptedException {
6. for (int i = 0; i < 10; i++) {
7. 500);
8. "staticMethod:" + i);
9. }
10. }
11.
12. public synchronized void normalMethod() throws InterruptedException {
13. for (int i = 0; i < 10; i++) {
14. 1000);
15. "normalMethod:" + i);
16. }
17. }
18.
19. public static void main(String[] args) {
20. final SynchronizedTest synchronizedTest = new SynchronizedTest();
21. new Thread(new Runnable() {
22. public void run() {
23. try {
24. synchronizedTest.normalMethod();
25. catch (InterruptedException e) {
26. e.printStackTrace();
27. }
28. }
29. "a");
30.
31. //为了验证获取到的锁都是当前调用这个方法的对象所属的类,特另新建一个对象
32. final SynchronizedTest synchronizedTest2 = new SynchronizedTest();
33.
34. new Thread(new Runnable() {
35. public void run() {
36. try {
37. synchronizedTest2.staticMethod();
38. catch (InterruptedException e) {
39. e.printStackTrace();
40. }
41. }
42. "b");
43.
44. thread1.start();
45. thread.start();
46. }
47. }
运行结果:
1. staticMethod:0
2. staticMethod:1
3. normalMethod:0
4. staticMethod:2
5. staticMethod:3
6. normalMethod:1
7. staticMethod:4
8. staticMethod:5
9. normalMethod:2
10. staticMethod:6
11. normalMethod:3
12. staticMethod:7
13. staticMethod:8
14. normalMethod:4
15. staticMethod:9
16. normalMethod:5
17. normalMethod:6
18. normalMethod:7
19. normalMethod:8
20. normalMethod:9
法2:语句块锁,直接看如下实例:
实例2:
1. package com.bijian.thread;
2.
3. public class SynchronizedTest {
4.
5. public final static Byte[] locks = new Byte[0];
6.
7. public static void staticMethod() throws InterruptedException {
8. synchronized(locks) {
9. for (int i = 0; i < 10; i++) {
10. 500);
11. "staticMethod:" + i);
12. }
13. }
14. }
15.
16. public void normalMethod() throws InterruptedException {
17. synchronized(locks) {
18. for (int i = 0; i < 10; i++) {
19. 1000);
20. "normalMethod:" + i);
21. }
22. }
23. }
24.
25. public static void main(String[] args) {
26. final SynchronizedTest synchronizedTest = new SynchronizedTest();
27. new Thread(new Runnable() {
28. public void run() {
29. try {
30. synchronizedTest.normalMethod();
31. catch (InterruptedException e) {
32. e.printStackTrace();
33. }
34. }
35. "a");
36.
37. new Thread(new Runnable() {
38. public void run() {
39. try {
40. SynchronizedTest.staticMethod();
41. catch (InterruptedException e) {
42. e.printStackTrace();
43. }
44. }
45. "b");
46.
47. thread1.start();
48. thread.start();
49. }
50. }
运行结果:
1. staticMethod:0
2. staticMethod:1
3. staticMethod:2
4. staticMethod:3
5. staticMethod:4
6. staticMethod:5
7. staticMethod:6
8. staticMethod:7
9. staticMethod:8
10. staticMethod:9
11. normalMethod:0
12. normalMethod:1
13. normalMethod:2
14. normalMethod:3
15. normalMethod:4
16. normalMethod:5
17. normalMethod:6
18. normalMethod:7
19. normalMethod:8
20. normalMethod:9