[关闭]
@huangyichun 2017-08-30T16:09:10.000000Z 字数 3979 阅读 729

Java多线程方法锁

多线程


本文主要介绍在多线程中对于普通方法和静态方法加锁调用产生的情况。
结论:

(1) 非静态方法锁默认为this也就是作用在对象上,静态方法的锁对应 Class实例(类加载会生成一个Class实例)
(2) 某一个时刻内,只有一个线程可以持有锁,无论几个方法

下面主要是验证这两个结论:

1.两个普通同步方法,开启两个线程调用

  1. class Number{
  2. public synchronized void getOne() {
  3. System.out.println("one");
  4. }
  5. public synchronized void getTwo(){
  6. System.out.println("two");
  7. }
  8. }
  1. public static void main(String[] args) {
  2. Number number = new Number();
  3. new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. number.getOne();
  7. }
  8. }).start();
  9. new Thread(new Runnable() {
  10. @Override
  11. public void run() {
  12. number.getTwo();
  13. }
  14. }).start();
  15. }

运行结果为:

one
two

2.在上面的基础上修改getOne()方法添加Thread.sleep()

  1. public synchronized void getOne() {
  2. try {
  3. Thread.sleep(3000);
  4. } catch (InterruptedException e) {
  5. e.printStackTrace();
  6. }
  7. System.out.println("one");
  8. }

运行结果为:

 one
 two

说明了两个方法调用的是同一个锁,锁先被线程一调用了,导致线程二处于等待状态,当线程一执行完后,线程二才能继续执行

3. 新增getThree()方法,同时开启三个线程调用这三个方法

  1. public class TestThread8Monitor {
  2. public static void main(String[] args) {
  3. Number number = new Number();
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. number.getOne();
  8. }
  9. }).start();
  10. new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. number.getTwo();
  14. }
  15. }).start();
  16. new Thread(new Runnable() {
  17. @Override
  18. public void run() {
  19. number.getThree();
  20. }
  21. }).start();
  22. }
  23. }
  24. class Number{
  25. public synchronized void getOne() {
  26. try {
  27. Thread.sleep(3000);
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. System.out.println("one");
  32. }
  33. public synchronized void getTwo(){
  34. System.out.println("two");
  35. }
  36. public void getThree(){//普通未加锁方法
  37. System.out.println("three");
  38. }
  39. }

运行结果:

three
one
two

说明:普通方法不受线程锁的影响,线程三直接执行,无须等待前面的线程释放锁

4.创建number的两个实例分别调用getOne()和getTwo()方法

  1. public class TestThread8Monitor {
  2. public static void main(String[] args) {
  3. Number number = new Number();
  4. Number number2 = new Number();
  5. new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. number.getOne();
  9. }
  10. }).start();
  11. new Thread(new Runnable() {
  12. @Override
  13. public void run() {
  14. number2.getTwo();
  15. }
  16. }).start();
  17. }
  18. }
  19. class Number{
  20. public synchronized void getOne() {
  21. try {
  22. Thread.sleep(3000);//等待3秒
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. }
  26. System.out.println("one");
  27. }
  28. public synchronized void getTwo(){
  29. System.out.println("two");
  30. }
  31. }

运行结果: two one
说明:调用加锁的普通方法,上锁的是this,也就是该对象,因此两个线程分别调用两个不同的对象,两者之间不存在互斥等待问题。

5.将getOne()改为静态方法,两个线程同时调用一个对象的不同方法

  1. public class TestThread8Monitor {
  2. public static void main(String[] args) {
  3. Number number = new Number();
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. number.getOne();
  8. }
  9. }).start();
  10. new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. number.getTwo();
  14. }
  15. }).start();
  16. }
  17. }
  18. class Number{
  19. public static synchronized void getOne() {
  20. try {
  21. Thread.sleep(3000);
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. System.out.println("one");
  26. }
  27. public synchronized void getTwo(){
  28. System.out.println("two");
  29. }
  30. }

运行结果: two one

说明: 静态方法锁和普通方法锁的目标不同。

6.同时将两个方法设置为静态方法,两个线程调用同一对象的两个方法

  1. public class TestThread8Monitor {
  2. public static void main(String[] args) {
  3. Number number = new Number();
  4. Number number2 = new Number();
  5. new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. number.getOne();
  9. }
  10. }).start();
  11. new Thread(new Runnable() {
  12. @Override
  13. public void run() {
  14. number2.getTwo();
  15. }
  16. }).start();
  17. }
  18. }
  19. class Number{
  20. public static synchronized void getOne() {
  21. try {
  22. Thread.sleep(3000);
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. }
  26. System.out.println("one");
  27. }
  28. public static synchronized void getTwo(){
  29. System.out.println("two");
  30. }
  31. }

运行结果: one two
说明:静态方法加锁是在类上的,也就是类的Class实例。因此两个线程调用两个对象的不同方法,结果却需要互斥调用

可重入锁ReentrantLock

  1. //非公平锁
  2. final boolean nonfairTryAcquire(int acquires) {
  3. final Thread current = Thread.currentThread();
  4. int c = getState();
  5. if (c == 0) {
  6. if (compareAndSetState(0, acquires)) {
  7. setExclusiveOwnerThread(current);
  8. return true;
  9. }
  10. }
  11. else if (current == getExclusiveOwnerThread()) {
  12. int nextc = c + acquires;
  13. if (nextc < 0) // overflow
  14. throw new Error("Maximum lock count exceeded");
  15. setState(nextc);
  16. return true;
  17. }
  18. return false;
  19. }
  1. //公平锁
  2. protected final boolean tryAcquire(int acquires) {
  3. final Thread current = Thread.currentThread();
  4. int c = getState();
  5. if (c == 0) {
  6. if (!hasQueuedPredecessors() &&
  7. compareAndSetState(0, acquires)) {
  8. setExclusiveOwnerThread(current);
  9. return true;
  10. }
  11. }
  12. else if (current == getExclusiveOwnerThread()) {
  13. int nextc = c + acquires;
  14. if (nextc < 0)
  15. throw new Error("Maximum lock count exceeded");
  16. setState(nextc);
  17. return true;
  18. }
  19. return false;
  20. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注