彻底搞懂Java多线程(二)

时间:2022-09-10 14:05:16

Java中的锁

Java中的加锁操作有两种:

1.synchronized锁(jvm层的解决方案,也叫监视器锁)

在操作系统的层面使用的是互斥锁(mutex lock)

在Java中放在了对象头中。

2.手动锁Lock

操作锁的流程

  • 1.尝试获取锁
  • 2.使用锁
  • 3.释放锁

synchronized锁

  1. package ThreadDeom;
  2. /**
  3. * user:ypc;
  4. * date:2021-06-12;
  5. * time: 14:12;
  6. */
  7. class Counter2 {
  8. private static volatile int count = 0;
  9. public void increase() {
  10. for (int i = 0; i < 10000; i++) {
  11. count++;
  12. }
  13. }
  14. public void decrease() {
  15. for (int i = 0; i < 10000; i++) {
  16. count--;
  17. }
  18. }
  19. public int getCount() {
  20. return count;
  21. }
  22. }
  23.  
  24. public class ThreadDemo19 {
  25. public static void main(String[] args) throws InterruptedException {
  26. //声明锁对象,任何的对象都可以作为锁
  27. Object lock = new Object();
  28. Counter2 counter2 = new Counter2();
  29. Thread thread1 = new Thread(new Runnable() {
  30. @Override
  31. public void run() {
  32. //使用锁
  33. synchronized (lock) {
  34. counter2.decrease();
  35. }
  36. }
  37. });
  38. Thread thread2 = new Thread(() -> {
  39. synchronized (lock) {
  40. counter2.increase();
  41. }
  42. });
  43. thread1.start();
  44. thread2.start();
  45. thread1.join();
  46. thread2.join();
  47. System.out.println(counter2.getCount());
  48. }
  49. }

结果是:

彻底搞懂Java多线程(二)

synchronized使用场景

 

1.使用synchronized来修饰代码块(可以给任意的对象进行加锁操作)

  1. public class ThreadDemo19 {
  2. public static void main(String[] args) throws InterruptedException {
  3. //声明锁对象,任何的对象都可以作为锁
  4. Object lock = new Object();
  5. Counter2 counter2 = new Counter2();
  6. Thread thread1 = new Thread(new Runnable() {
  7. @Override
  8. public void run() {
  9. //使用锁
  10. synchronized (lock) {
  11. counter2.decrease();
  12. }
  13. }
  14. });
  15. Thread thread2 = new Thread(() -> {
  16. synchronized (lock) {
  17. counter2.increase();
  18. }
  19. });
  20. thread1.start();
  21. thread2.start();
  22. thread1.join();
  23. thread2.join();
  24. System.out.println(counter2.getCount());
  25. }
  26. }

彻底搞懂Java多线程(二)

2.使用synchronized来修饰静态方法(对当前的类进行加锁的操作)

  1. package ThreadDeom;
  2. /**
  3. * user:ypc;
  4. * date:2021-06-12;
  5. * time: 14:02;
  6. */
  7. class Counter1 {
  8. private static volatile int count = 0;
  9. public void increase() {
  10. for (int i = 0; i < 10000; i++) {
  11. count++;
  12. }
  13. }
  14. public void decrease() {
  15. for (int i = 0; i < 10000; i++) {
  16. count--;
  17. }
  18. }
  19. public int getCount() {
  20. return count;
  21. }
  22. }
  23.  
  24. public class ThreadDemo18 {
  25. public static void main(String[] args) throws InterruptedException {
  26. Counter1 counter1 = new Counter1();
  27. Thread thread1 = new Thread(new Runnable() {
  28. @Override
  29. public void run() {
  30. counter1.decrease();
  31. }
  32. });
  33. Thread thread2 = new Thread(() -> {
  34. counter1.increase();
  35. });
  36. thread1.start();
  37. thread2.start();
  38. thread1.join();
  39. thread2.join();
  40. System.out.println(counter1.getCount());
  41. }
  42. }

彻底搞懂Java多线程(二)

3.使用synchronized来修饰普通的方法(对当前类的实例来进行加锁)

  1. package ThreadDeom;
  2. /**
  3. * user:ypc;
  4. * date:2021-06-12;
  5. * time: 14:12;
  6. */
  7. public class ThreadDemo20 {
  8. private static int num = 0;
  9. private static final int maxSize = 100000;
  10. public static void main(String[] args) throws InterruptedException {
  11. ThreadDemo20 threadDemo20 = new ThreadDemo20();
  12. Thread thread1 = new Thread(new Runnable() {
  13. @Override
  14. public void run() {
  15. threadDemo20.increase();
  16. }
  17. });
  18. Thread thread2 = new Thread(new Runnable() {
  19. @Override
  20. public void run() {
  21. threadDemo20. decrease();
  22. }
  23. });
  24. thread1.start();
  25. thread2.start();
  26. thread1.join();
  27. thread2.join();
  28. System.out.println(num);
  29. }
  30. //给静态的方法进行加锁,被加的锁是当前的对象。
  31. // public synchronized static void increase(){
  32. //给普通的方法进行加锁的操作
  33. public synchronized void increase() {
  34. for (int i = 0; i < maxSize; i++) {
  35. num++;
  36. }
  37. }
  38. // public synchronized static void decrease(){
  39. public synchronized void decrease() {
  40. for (int i = 0; i < maxSize; i++) {
  41. num--;
  42. }
  43. }
  44. }

彻底搞懂Java多线程(二)

synchronized注意事项

 

1.加锁的时候一定要使用同一把锁对象

Lock类的使用

也叫手动锁

  1. package ThreadDeom;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * user:ypc;
  6. * date:2021-06-12;
  7. * time: 18:32;
  8. */
  9. public class ThreadDemo22 {
  10. private static int number = 0;
  11. private static final int maxSize = 100000;
  12. public static void main(String[] args) {
  13. //创建lock锁对象,lock是接口,不能实列化
  14. Lock lock = new ReentrantLock();
  15.  
  16. Thread thread1 = new Thread(() -> {
  17. for (int i = 0; i < maxSize; i++) {
  18. lock.lock();
  19. try {
  20. number++;
  21. } finally {
  22. lock.unlock();
  23. }
  24. }
  25. });
  26.  
  27. Thread thread2 = new Thread(() -> {
  28. for (int i = 0; i < maxSize; i++) {
  29. lock.lock();
  30. try {
  31. number--;
  32. } finally {
  33. lock.unlock();
  34. }
  35. }
  36. });
  37. System.out.println(number);
  38. }
  39. }

彻底搞懂Java多线程(二)

Lock锁使用的注意事项

lock()操作一定要放在try外面

如果放在try的里面:

1.try中抛出了异常,还没有加锁就释放了finally中的锁的操作了

2.如果放在了try,没加锁就释放了锁,就会抛出异常,就会将业务代码中的异常吞噬掉