java的aop是线程安全_java并发编程:多线程和线程锁的思考

1、当前线程的状态,所持有的锁是否释放

持有锁的线程不释放锁

线程执行同步代码块或同步方法时,程序调用Thread.sleep(Long l)、Thread.yield()方法暂停当前线程的执行,不释放锁;

线程执行同步代码块时,其它线程调用该线程suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)

尽量避免使用suspend()和resume()来控制线程

持有锁的线程会释放锁

当前线程的同步方法、同步代码块执行结束

当前线程的同步方法、同步代码块遇到break、return终止该代码块、该方法的继续执行

当前线程的同步方法、同步代码块中出现了未处理Error和Exception,导致异常结束

当前线程在同步方法、同步代码块中执行了线程所属对象的wait()方法,当前线程暂停,并释放锁

所以说:

* 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内(下面的代码锁对象就是queue,先获得该对象,再在代码块中使用wait()和notify()方法阻塞唤醒线程)

* 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A

* 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行

* 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)

* obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行

* 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。

1 public classTest {2 private int queueSize = 10;3 private PriorityQueue queue = new PriorityQueue(queueSize);4

5 public static voidmain(String[] args) {6 Test test = newTest();7 Producer producer = test.newProducer();8 Consumer consumer = test.newConsumer();9

10 producer.start();11 consumer.start();12 }13

14 class Consumer extendsThread{15

16 @Override17 public voidrun() {18 consume();19 }20

21 private voidconsume() {22 while(true){23 synchronized(queue) {24 while(queue.size() == 0){25 try{26 System.out.println("队列空,等待数据");27 queue.wait();28 } catch(InterruptedException e) {29 e.printStackTrace();30 queue.notify();31 }32 }33 queue.poll(); //每次移走队首元素

34 queue.notify();35 System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");36 }37 }38 }39 }40

41 class Producer extendsThread{42

43 @Override44 public voidrun() {45 produce();46 }47

48 private voidproduce() {49 while(true){50 synchronized(queue) {51 while(queue.size() ==queueSize){52 try{53 System.out.println("队列满,等待有空余空间");54 queue.wait();55 } catch(InterruptedException e) {56 e.printStackTrace();57 queue.notify();58 }59 }60 queue.offer(1); //每次插入一个元素

61 queue.notify();62 System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));63 }64 }65 }66 }67 }

wait()/sleep()的区别

前面讲了wait/notify机制,Thread还有一个sleep()静态方法,它也能使线程暂停一段时间。sleep与wait的不同点是:sleep并不释放锁,并且sleep的暂停和wait暂停是不一样的。obj.wait会使线程进入obj对象的等待集合中并等待唤醒。

但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException。

如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程。

需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到wait()/sleep()/join()后,就会立刻抛出InterruptedException。

查看Object.wait()API 描述如下:

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

The current thread must ownthis object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

其中“the thread releases ownership of this monitor” 说道当前线程会释放这个对象监控器的所有权。

1 public classTest {2 private int queueSize = 10;3 private ArrayBlockingQueue queue = new ArrayBlockingQueue(queueSize);4

5 public static voidmain(String[] args) {6 Test test = newTest();7 Producer producer = test.newProducer();8 Consumer consumer = test.newConsumer();9

10 producer.start();11 consumer.start();12 }13

14 class Consumer extendsThread{15

16 @Override17 public voidrun() {18 consume();19 }20

21 private voidconsume() {22 while(true){23 try{24 queue.take();25 System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");26 } catch(InterruptedException e) {27 e.printStackTrace();28 }29 }30 }31 }32

33 class Producer extendsThread{34

35 @Override36 public voidrun() {37 produce();38 }39

40 private voidproduce() {41 while(true){42 try{43 queue.put(1);44 System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));45 } catch(InterruptedException e) {46 e.printStackTrace();47 }48 }49 }50 }51 }

有没有发现,使用阻塞队列代码要简单得多,不需要再单独考虑同步和线程间通信的问题。

原文:https://blog.csdn.net/csdn_g_y/article/details/79751803

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2023年,Java开发1-2年的程序员应该对Spring、MySQL和多线程技术有一定的掌握程度。以下是每个技术点的详细说明: 1. Spring框架: - Spring IoC(控制反转)和DI(依赖注入):了解IoC和DI的原理和概念,能够使用注解或XML配置实现依赖注入。 - Spring AOP(面向切面编程):了解AOP的概念和原理,能够使用切面进行日志记录、事务管理等操作。 - Spring MVC:熟悉Spring MVC框架的基本原理和使用方法,能够进行Web应用的开发和请求处理。 - Spring Boot:掌握Spring Boot的基本概念和使用方法,能够快速搭建和配置Spring应用。 2. MySQL数据库: - 数据库基础知识:了解数据库的基本概念、表设计和SQL语言,能够编写常见的SQL查询和更新语句。 - 数据库连接和事务管理:掌握数据库连接池的使用,了解事务的概念和ACID特性,能够进行事务管理和异常处理。 - 索引和性能优化:了解索引的原理和创建方法,能够进行索引优化和查询性能调优。 3. 多线程技术: - 线程基础知识:了解线程的概念和生命周期,能够创建和启动线程,并进行基本的线程同步和通信。 - 线程安全:了解线程安全的概念和常见的线程安全问题,能够使用synchronized关键字或Lock接口实现线程安全。 - 并发集合类:熟悉Java并发包中的并发集合类(如ConcurrentHashMap、ConcurrentLinkedQueue)的使用。 - 线程池:了解线程池的概念和使用方法,能够创建和配置线程池,并进行线程调度和任务管理。 请注意,以上只是技术点的基本要求,实际工作中可能还会涉及到更深入的知识和技能。因此,持续学习和实践是提高技术水平的关键。同时,根据具体的项目需求和行业趋势,也可能会有其他相关技术需要掌握。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值