Java多线程run方法中直接调用service业务类应注意的问题及解决

目录
  • 多线程run方法中直接调用service业务类应注意
    • 图解如下
  • 多线程知识点
    • 线程启动的四种方式
    • 使用@Aysnc注解实现多线程
    • 用户线程与守护线程的区别
    • 线程的六种状态
    • Java锁的可重入性
    • 线程池的四种拒绝策略
    • sleep和wait的区别
    • 为什么wait(),notify(),notifyAll()在对象中,而不在Thread类中

多线程run方法中直接调用service业务类应注意

Java多线程run方法里边使用service业务类会产生java.lang.NullPointerException异常的问题,这是由于spring注入的业务类为null,或者直接new的业务对象也为null。

多线程为了线程安全会防止注入,因此在想使用service业务类时,需要使用ApplicationContext的方式获取bean的方法获取service类。

获取ApplicationContext的类要实现ApplicationContextAware接口,如下:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class ApplicationContextUtil implements ApplicationContextAware {

	private static ApplicationContext context;
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		this.context = context;
	}
	public static ApplicationContext getContext() {
		return context;
	}
}

然后在run方法里使用以上方法创建业务对象,如下:

XXXServiceI xxxService = ApplicationContextUtil.getContext.getBean(XXXServiceI.class);

这样就能正常使用该业务类了。

图解如下

多线程知识点

线程启动的四种方式

1.、继承Thread类重写Thread的run方法,在run方法中进行操作,用start方法启动线程

2、继承Runnable接口,实现run方法,在run方法中进行操作,需要传入当前类的实例对象创建一个Thread实例,然后调用start方法启动线程

3、实现Callable接口,重写call()方法,需要注意的是,前两种方法都是不需要响应的,直接就执行了,但是实现Callable接口,重写call()方法则是需要等待线程响应的,所以虽然启动了其他线程,但是却是一个线程在执行,并不能算标准的多线程。

4、线程池

使用@Aysnc注解实现多线程

同一个类中,方法A 引用方法B 方法B加异步@Async注解 不会有效

被加@Async方法和调用方 不能再同一个类中

用户线程与守护线程的区别

Java内创建的线程默认是创建用户线程,比如new Thread(线程对象).start

    Thread thread = new Thread();
    // 默认为false,都是用户线程
    thread.setDaemon(true); // 表示设置为守护线程
    thread.setDaemon(false); // 表示设置为用户线程
  • 用户线程:不zhi随着其他线程的死亡而死亡,只有两种情况dao死掉,一是在运行中出现异常而终止,二是正常把程序执行完毕,线程死亡
  • 守护线程:随着用户线程的死亡而死亡,当用户线程死完了守护线程也死了,比如gc垃圾回收线程。用户线程存在,那gc就有活着的必要,反之就没用了。

线程的六种状态

1. New:初始状态,线程被创建,没有调用start()

2. Runnable:运行状态,Java线程把操作系统中的就绪和运行两种状态统一称为“运行中”

3. Blocked:阻塞,线程进入等待状态,线程因为某种原因,放弃了CPU的使用权

  • 阻塞的几种情况:
  • A. 等待阻塞:运行的线程执行了wait(),JVM会把当前线程放入等待队列
  • B. 同步阻塞:运行的线程在获取对象的同步锁时,如果该同步锁被其他线程占用了,JVM会把当前线程放入锁池中
  • C. 其他阻塞:运行的线程执行sleep(),join()或者发出IO请求时,JVM会把当前线程设置为阻塞状态,当sleep()执行完,join()线程终止,IO处理完毕线程再次恢复

4. Waiting:等待状态

5. timed_waiting:超时等待状态,超时以后自动返回

6. terminated:终止状态,当前线程执行完毕

Java锁的可重入性

java锁的可重入性机制可以解决下面这个问题,直接上代码:

 public class Demo1 {
    public synchronized void functionA(){
        System.out.println("iAmFunctionA");
        functionB();
    }
    public synchronized void functionB(){
        System.out.println("iAmFunctionB");
    }

假设Java没有提供synchronized 强制原子性的内部锁机制:functionA()和functionB()都是同步方法,当线程进入funcitonA()会获得该类的对象锁,这个锁"new Demo1()",在functionA()对方法functionB()做了调用,但是functionB()也是同步的,因此该线程需要再次获得该对象锁(new Demo1()),但是JVM会认为这个线程已经获取了此对象的锁,而不能再次获取,从而无法调用functionB()方法,从而造成死锁。

线程池的四种拒绝策略

当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务

ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

sleep和wait的区别

  • sleep是线程中的方法,但是wait是Object中的方法
  • sleep方法不会释放lock,但是wait会释放,而且会加入到等待队列中
  • sleep不需要被唤醒,但是wait需要

为什么wait(),notify(),notifyAll()在对象中,而不在Thread类中

java中锁的级别是对象级而不是线程级,每个对象都有锁,通过线程获得。如果wait()方法在线程中,线程正在等待的是哪个锁就不明显了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java多线程异步调用性能调优方法详解

    目录 概述 同步调用和异步调用 Future类图 Future的不足 代码 代码地址 Test PaymentService CheckService OrderService 总结 概述 大型电商公司的支付聚合服务都有这类的场景: 调用校验服务校验待生成的订单是否合法 订单服务生成订单(校验服务和订单服务没有依赖关系) 调用1和2,支付服务实现支付核心的功能 结合步骤1至3完成支付服务的聚合调用 ​假如步骤1的耗时5秒,步骤2的耗时3秒,步骤3的耗时2秒,如果你是架构师,要求:​ 1.请实现微

  • 基于Java回顾之多线程同步的使用详解

    首先阐述什么是同步,不同步有什么问题,然后讨论可以采取哪些措施控制同步,接下来我们会仿照回顾网络通信时那样,构建一个服务器端的"线程池",JDK为我们提供了一个很大的concurrent工具包,最后我们会对里面的内容进行探索. 为什么要线程同步? 说到线程同步,大部分情况下, 我们是在针对"单对象多线程"的情况进行讨论,一般会将其分成两部分,一部分是关于"共享变量",一部分关于"执行步骤". 共享变量 当我们在线程对象(Run

  • 举例解析Java多线程编程中需要注意的一些关键点

    1. 同步方法或同步代码块? 您可能偶尔会思考是否要同步化这个方法调用,还是只同步化该方法的线程安全子集.在这些情况下,知道 Java 编译器何时将源代码转化为字节代码会很有用,它处理同步方法和同步代码块的方式完全不同. 当 JVM 执行一个同步方法时,执行中的线程识别该方法的 method_info 结构是否有 ACC_SYNCHRONIZED 标记设置,然后它自动获取对象的锁,调用方法,最后释放锁.如果有异常发生,线程自动释放锁. 另一方面,同步化一个方法块会越过 JVM 对获取对象锁和异常

  • Java多线程run方法中直接调用service业务类应注意的问题及解决

    目录 多线程run方法中直接调用service业务类应注意 图解如下 多线程知识点 线程启动的四种方式 使用@Aysnc注解实现多线程 用户线程与守护线程的区别 线程的六种状态 Java锁的可重入性 线程池的四种拒绝策略 sleep和wait的区别 为什么wait(),notify(),notifyAll()在对象中,而不在Thread类中 多线程run方法中直接调用service业务类应注意 Java多线程run方法里边使用service业务类会产生java.lang.NullPointerE

  • 浅谈java多线程 join方法以及优先级方法

    join: 当A线程执行到了B线程的.join()方法时,A就会等待.等B线程都执行完,A才会执行. join可以用来临时加入线程执行. 1.线程使用join方法,主线程就停下,等它执行完,那么如果该线程冻结了,主线程就挂了,这也是为什么线程要抛异常的原因 2.当两个或以上线程开启了,这个A线程才使用join方法,那么主线程还是停下,这几个个线程交替进行,直到A执行完,主线程才复活 1. tostring(),方法,获取线程具体的名字,优先级 2. 优先级代表抢资源的频率 3. java中设置有

  • Java多线程回调方法实例解析

    所谓回调,就是客户程序C调用服务程序S中的某个方法A,然后S又在某个时候反过来调用C中的某个方法B,对于C来说,这个B便叫做回调方法. 下面看一个实际例子来理解: 本示例设置一个提问者,一个回答者,而回答者需要回答提问者一个很深奥的问题时,这时需要很多时间去查找,提问者又开始做其他的事情, 等回答者找到答案后,再把答案告诉提问者. 一.提问者的类 涉及到长时间的思考,要sleep,要继承Thread package com.xykj.thread; public class XiaoZhang

  • java多线程join()方法的作用和实现原理解析(应用场景)

    1.join() 方法的作用 这个方法的作用是先将当前线程挂起,待其他线程结束后在执行当前线程的代码: 2.应用场景 比如有三个人小红.小李.小王, 三个人相约一起去酒店吃饭,菜已经点好了, 三个人从不同的地方出发,只有三个人都到了酒店之后才会开始上菜:那么这三个人就分别代表三个线程,这三个线程执行完之后才会执行 "上菜" 的代码逻辑, 代码示例 package com.Lock; /** * join方法示例 * 比如有三个人小红.小李.小王, 三个人相约一起去酒店吃饭,菜已经点好了

  • 详解Java多线程tryLock()方法使用

    tryLock(long time, TimeUnit unit) 的作用在给定等待时长内锁没有被另外的线程持有,并且当前线程也没有被中断,则获得该锁,通过该方法可以实现锁对象的限时等待. package com.wkcto.lock.reentrant; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** *tryLock(long time, TimeUnit u

  • Java多线程join方法实例代码

    本文研究的主要是Java多线程中join方法的使用问题,以下文为具体实例. Thread的非静态方法join()让一个线程B"加入"到另外一个线程A的尾部.在A执行完毕之前,B不能工作.例如: Thread t = new MyThread(); t.start(); t.join(); 另外,join()方法还有带超时限制的重载版本. 例如t.join(5000);则让线程等待5000毫秒,如果超过这个时间,则停止等待,变为可运行状态. 线程的加入join()对线程栈导致的结果是线程

  • Java多线程高并发中解决ArrayList与HashSet和HashMap不安全的方案

    1.ArrayList的线程不安全解决方案 将main方法的第一行注释打开,多执行几次,会看到如下图这样的异常信息:

  • Java多线程高并发中的Fork/Join框架机制详解

    1.Fork/Join框架简介 Fork/Join 它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出.Fork/Join 框架要完成两件事情: Fork:把一个复杂任务进行分拆,大事化小 :把一个复杂任务进行分拆,大事化小 Join:把分拆任务的结果进行合并 在 Java 的 Fork/Join 框架中,使用两个类完成上述操作: ForkJoinTask: 我们要使用 Fork/Join 框架,首先需要创建一个 ForkJoin 任务.该类提供了

  • Spring main方法中如何调用Dao层和Service层的方法

    目录 Spring main方法调用Dao层和Service层的方法 如何在普通类中直接访问service层或dao层 第一种方案 第二种方案 Spring main方法调用Dao层和Service层的方法 在web环境中,一般serviceImpl中的dao之类的数据库连接都由容器启动的时候创建好了,不会报错. 但是在main中,没有这个环境,所以需要获取环境: ApplicationContext ctx = new FileSystemXmlApplicationContext("src/

  • JAVA多线程之方法 JOIN详解及实例代码

    JAVA多线程 JOIN 对于Java开发人员,多线程应该是必须熟练应用的知识点,特别是开发基于Java语言的产品.本文将深入浅出的表述Java多线程的知识点,在后续的系列里将侧重于Java5由Doug Lea教授提供的Concurrent并行包的设计思想以及具体实现与应用. 如何才能深入浅出呢,我的理解是带着问题,而不是泛泛的看.所以该系列基本以解决问题为主,当然我也非常希望读者能够提出更好的解决问题的方案以及提出更多的问题.由于水平有限,如果有什么错误之处,请大家提出,共同讨论,总之,我希望

随机推荐