java多线程Lock关键字、Condition

灰太狼 2022-03-20 09:59 424阅读 0赞

一、Lock关键字相对于传统锁synchronized更加面向对象

1、示例:在多线程情况下,按顺序输出指定字符串

定义一个类专门用于输出字符串

  1. public class ThreadLockDemo {
  2. int len = s.length();
  3. for (int i = 0; i < len; i++) {
  4. System.out.print(s.charAt(i));
  5. }
  6. System.out.println();
  7. }
  8. }

多线程访问:

  1. public static void main(String[] args) {
  2. ThreadLockDemo threadLockDemo = new ThreadLockDemo();
  3. new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. for (int i = 0; i < 10; i++) {
  7. try {
  8. Thread.sleep(10);
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. threadLockDemo.printLetter("liucui");
  13. }
  14. }
  15. }).start();
  16. new Thread(new Runnable() {
  17. @Override
  18. public void run() {
  19. for (int i = 0; i < 10; i++) {
  20. try {
  21. Thread.sleep(10);
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. threadLockDemo.printLetter("wuchengfeng");
  26. }
  27. }
  28. }).start();
  29. }

输出结果:

wuchengfenliucuig

liucui
wuchengfeng
wuchengfeng
liucui
wluiucui
chengfeng
wuchengfeng
liucui
wliucuuchengfeng
i
liucui
wuchengfeng
wliucui
uchengfeng
wucliucuihengf
eng
wluiucui
chengfeng
由控制台输出可以看出,printLetter方法在多线程访问下被打断,导致输出混乱,这时候使用lock关键字可以有效的解决这个问题

重新改写ThreadLockDemo

  1. public class ThreadLockDemo {
  2. Lock lock = new ReentrantLock();
  3. public void printLetter(String s) {
  4. //加锁
  5. lock.lock();
  6. try {
  7. int len = s.length();
  8. for (int i = 0; i < len; i++) {
  9. System.out.print(s.charAt(i));
  10. }
  11. System.out.println();
  12. } finally {
  13. //锁释放
  14. lock.unlock();
  15. }
  16. }
  17. }

liucui
wuchengfeng
liucui
wuchengfeng
liucui
wuchengfeng
wuchengfeng
liucui
liucui
wuchengfeng
liucui
wuchengfeng
wuchengfeng
liucui
liucui

二、ReadWriteLock读写锁,共享数据的时候,多个线程只有一个线程可以写数据,多个线程可以读数据

  1. public class ThreadLockDemo {
  2. ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
  3. public void readData() {
  4. //保证多个线程可以同时读数据
  5. readWriteLock.readLock().lock();
  6. System.out.println(Thread.currentThread().getName()+"------------开始读数据--------------------------");
  7. try {
  8. Thread.sleep((long)Math.random()*1000);
  9. } catch (Exception e) {
  10. e.printStackTrace();
  11. }
  12. System.out.println(Thread.currentThread().getName()+"------------数据读完了--------------------------");
  13. readWriteLock.readLock().unlock();
  14. }
  15. public void writeData() {
  16. //保证多个线程同时只有一个线程可以写数据
  17. readWriteLock.writeLock().lock();
  18. System.out.println(Thread.currentThread().getName()+"#############开始写数据#############-");
  19. try {
  20. Thread.sleep((long)Math.random()*1000);
  21. } catch (Exception e) {
  22. e.printStackTrace();
  23. }
  24. System.out.println(Thread.currentThread().getName()+"#############数据写完了#############");
  25. readWriteLock.writeLock().unlock();
  26. }
  27. }

三、Condition替换传统的wait、notify功能

  1. static class ThreadSubMain {
  2. private boolean isWait = true;
  3. Lock lock = new ReentrantLock();
  4. Condition condition = lock.newCondition();
  5. /// 子线程循环20次
  6. void subExcute(int i) {
  7. lock.lock();
  8. while (!isWait) {
  9. try {
  10. condition.await();//类似this.wait()
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. for (int j = 0; j < 2; j++) {
  16. System.out.println("第" + i + "个,第" + j + "子线程--->" + Thread.currentThread().getName());
  17. }
  18. // 当子线程执行两次后,改变标识符,唤醒主线程执行;
  19. isWait = false;
  20. condition.signal();
  21. lock.unlock();
  22. }
  23. /// 主线程循环10次
  24. void mainExcute() {
  25. lock.lock();
  26. for (int i = 0; i < 10; i++) {
  27. while (isWait) {
  28. try {
  29. condition.await();
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. System.out.println("第" + i + "个主线程--->" + Thread.currentThread().getName());
  34. }
  35. // 当主线程执行一次后,改变标识符,唤醒主子线程
  36. isWait = true;
  37. condition.signal();/类似this.notify()
  38. }
  39. lock.unlock();
  40. }
  41. }
  42. public static void main(String[] args) {
  43. ThreadSubMain threadSubMain = new ThreadSubMain();
  44. new Thread(new Runnable() {
  45. @Override
  46. public void run() {
  47. for (int i = 0; i < 10; i++) {
  48. threadSubMain.subExcute(i);
  49. }
  50. }
  51. }).start();
  52. threadSubMain.mainExcute();
  53. }

发表评论

表情:
评论列表 (有 0 条评论,424人围观)

还没有评论,来说两句吧...

相关阅读