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、线程池
同一个类中,方法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锁的可重入性机制可以解决下面这个问题,直接上代码:
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()方法,从而造成死锁。
Lorsque la file d'attente du cache des tâches du pool de threads est pleine et que le nombre de threads dans le pool de threads atteint maximumPoolSize, s'il y a encore des tâches qui arrivent, la stratégie de rejet des tâches sera adoptée. généralement quatre stratégies :
ThreadPoolExecutor.AbortPolicy
: abandonnez la tâche et lancez RejectedExecutionException. ThreadPoolExecutor.AbortPolicy
:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy
:丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy
:丢弃队列最前面的任务,然后重新提交被拒绝的任务
ThreadPoolExecutor.CallerRunsPolicy
ThreadPoolExecutor.DiscardPolicy
: abandonnez la tâche, mais ne lancez pas d'exception.
ThreadPoolExecutor.DiscardOldestPolicy
: supprimez la tâche la plus en avant de la file d'attente, puis soumettez à nouveau la tâche rejetée ThreadPoolExecutor.CallerRunsPolicy
: traité par le thread appelant (le thread qui a soumis la tâche) Cette tâcheLa différence entre sleep et waitCe qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!