用法

  1. 用在 非静态方法 上(执行该方法的时候,对这个对象进行加锁)
  2. 用在 静态方法 上(执行该方法的时候,对整个类进行加锁)
  3. 代码块 中对某个对象加锁(在执行该代码块的时候,对该对象进行加锁)
  4. 代码块 中对某个类进行加锁(在执行该代码块的时候,对该类进行加锁)

1. 用在非静态方法上

  1. public class TestThread {
  2. public static void main(String[] args) {
  3. ExecutorService service = Executors.newCachedThreadPool();
  4. Thread thread = new Thread(new ThreadTest());
  5. service.submit(thread);
  6. service.submit(thread);
  7. service.shutdown();
  8. }
  9. }
  10. public class ThreadTest implements Runnable {
  11. public synchronized void run() {
  12. System.out.println("Start");
  13. try {
  14. Thread.sleep(1000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println("End");
  19. }
  20. }
  21. 输出结果:
  22. Start
  23. End
  24. Start
  25. End

可以看到,synchronized作用于非静态方法上,实际上是对对象加锁,对于同一对象,执行是同步的,而如果两个线程属于不同对象,则会导致这个锁失效:

  1. public class TestThread {
  2. public static void main(String[] args) {
  3. ExecutorService service = Executors.newCachedThreadPool();
  4. Thread thread1 = new Thread(new ThreadTest());
  5. Thread thread2 = new Thread(new ThreadTest());
  6. service.submit(thread1);
  7. service.submit(thread2);
  8. service.shutdown();
  9. }
  10. }
  11. public class TestThread {
  12. public static void main(String[] args) {
  13. ExecutorService service = Executors.newCachedThreadPool();
  14. Thread thread1 = new Thread(new ThreadTest());
  15. Thread thread2 = new Thread(new ThreadTest());
  16. service.submit(thread1);
  17. service.submit(thread2);
  18. service.shutdown();
  19. }
  20. }
  21. 输出结果:
  22. Start
  23. Start
  24. End
  25. End

对于不同的对象,执行的过程不是同步的,可知synchronized用在非静态方法上,是对这个对象加锁

2. 用在静态方法上

  1. public class TestThread {
  2. public static void main(String[] args) {
  3. ExecutorService service = Executors.newCachedThreadPool();
  4. Thread thread1 = new Thread(new ThreadTest());
  5. Thread thread2 = new Thread(new ThreadTest());
  6. service.submit(thread1);
  7. service.submit(thread2);
  8. service.shutdown();
  9. }
  10. }
  11. public class ThreadTest implements Runnable {
  12. public void run() {
  13. Test.print();
  14. }
  15. }
  16. public class Test {
  17. public synchronized static void print() {
  18. System.out.println("Start");
  19. try {
  20. Thread.sleep(1000);
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. System.out.println("End");
  25. }
  26. }
  27. 输出结果:
  28. Start
  29. End
  30. Start
  31. End

静态方法是属于类的属性,存放在方法区中,与实例对象无关,所以 synchronized 用在静态方法上实际上是对整个类加锁,所以就算是不同实例,结果也是同步的,如果是同一类同一对象,也是一样的结果

3. 在代码块中对类进行加锁

  1. public class TestThread {
  2. public static void main(String[] args) {
  3. ExecutorService service = Executors.newCachedThreadPool();
  4. Thread thread = new Thread(new ThreadTest());
  5. service.submit(thread);
  6. service.submit(thread);
  7. service.shutdown();
  8. }
  9. }
  10. public class ThreadTest implements Runnable {
  11. public void run() {
  12. synchronized (ThreadTest.class) {
  13. System.out.println("Start");
  14. try {
  15. Thread.sleep(1000);
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. System.out.println("End");
  20. }
  21. }
  22. }
  23. 输出结果:
  24. Start
  25. End
  26. Start
  27. End

对class类进行加锁,跟作用在静态方法上效果是相同的,只针对类,而不是针对具体对象

4. 在代码块中对对象进行加锁

  1. public class TestThread {
  2. public static void main(String[] args) {
  3. ExecutorService service = Executors.newCachedThreadPool();
  4. Thread thread = new Thread(new ThreadTest(new Test()));
  5. service.submit(thread);
  6. service.submit(thread);
  7. service.shutdown();
  8. }
  9. }
  10. public class ThreadTest implements Runnable {
  11. private final Test test;
  12. public ThreadTest(Test test) {
  13. this.test = test;
  14. }
  15. public void run() {
  16. synchronized (test) {
  17. test.print();
  18. }
  19. }
  20. }
  21. public class Test {
  22. public void print() {
  23. System.out.println("Start");
  24. try {
  25. Thread.sleep(1000);
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. System.out.println("End");
  30. }
  31. }
  32. 输出结果:
  33. Start
  34. End
  35. Start
  36. End

在run方法中,对Test对象进行了加锁,所以对相同对象执行方法是同步的,下面改写成两个不同对象:

  1. public class TestThread {
  2. public static void main(String[] args) {
  3. ExecutorService service = Executors.newCachedThreadPool();
  4. Thread thread1 = new Thread(new ThreadTest(new Test()));
  5. Thread thread2 = new Thread(new ThreadTest(new Test()));
  6. service.submit(thread1);
  7. service.submit(thread2);
  8. service.shutdown();
  9. }
  10. }
  11. // 其他代码与上面相同省略
  12. 输出结果:
  13. Start
  14. Start
  15. End
  16. End

可以看到,对不同对象这样加锁就不产生作用了