Spring无法通过@Value注入静态变量

对于spring static变量 spring不能注入static变量的原因,具体详情如下所示: Spring 依赖注入 是依赖 set方法 set方法是 是普通的对象方法 static变量是类的属性 只能在setAppId方法上加注解,另外class需要加 @Component等注解,这样spring才能扫描到 对于 import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;​@Componentpublic class GlobalValue {​   @Value(“${mysqk.db}”)   public static String DATABASE;​} DATABASE的值是null 但是静态的XXX如何注入呢?   上网查了很多的说法,其实很简单: import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;import lombok.Getter;​​@Componentpublic class GlobalValue {​   @Getter   public static String DATABASE;​   @Value(“${mysql.db:test}”)   public void setDatabase(String db) {       DATABASE […]

使用Redis实现内容过期提醒

# 业务场景 我们以订单功能为例说明下:生成订单后一段时间不支付订单会自动关闭。最简单的想法是设置定时任务轮询,但是每个订单的创建时间不一样,定时任务的规则无法设定,如果将定时任务执行的间隔设置的过短,太影响效率。还有一种想法,在用户进入订单界面的时候,判断时间执行相关操作。方式可能有很多,在这里介绍一种监听 Redis 键值对过期时间来实现订单自动关闭。 # 实现思路 在生成订单时,向 Redis 中增加一个 KV 键值对,K 为订单号,保证通过 K 能定位到数据库中的某个订单即可,V 可为任意值。假设,生成订单时向 Redis 中存放 K 为订单号,V 也为订单号的键值对,并设置过期时间为 30 分钟,如果该键值对在 30 分钟过期后能够发送给程序一个通知,或者执行一个方法,那么即可解决订单关闭问题。实现:通过监听 Redis 提供的过期队列来实现,监听过期队列后,如果 Redis 中某一个 KV 键值对过期了,那么将向监听者发送消息,监听者可以获取到该键值对的 K,注意,是获取不到 V 的,因为已经过期了,这就是上面所提到的,为什么要保证能通过 K 来定位到订单,而 V 为任意值即可。拿到 K 后,通过 K 定位订单,并判断其状态,如果是未支付,更新为关闭,或者取消状态即可。 # 开启 Redis key 过期提醒 修改 redis 相关事件配置。找到 redis 配置文件 redis.conf,查看 notify-keyspace-events 配置项,如果没有,添加 […]

多线程面试题-2021

Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多、越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的。这篇文章主要是对多线程的问题进行总结的,因此罗列了108个多线程的问题。 这些多线程的问题来源于各大网站,可能有些问题网上有、可能有些问题对应的答案也有、也可能有些各位网友也都看过,但是本文写作的重心就是所有的问题都会按照自己的理解回答一遍,不会去看网上的答案,因此可能有些问题讲的不对,能指正的希望大家不吝指教。 # 106个问题汇总 1、多线程有什么用? 一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡。所谓”知其然知其所以然”,”会用”只是”知其然”,”为什么用”才是”知其所以然”,只有达到”知其然知其所以然”的程度才可以说是把一个知识点运用自如。OK,下面说说我对这个问题的看法: (1)发挥多核CPU的优势 随着工业的进步,现在的笔记本、台式机乃至商用的应用服务器至少也都是双核的,4核、8核甚至16核的也都不少见,如果是单线程的程序,那么在双核CPU上就浪费了50%,在4核CPU上就浪费了75%。单核CPU上所谓的”多线程”那是假的多线程,同一时间处理器只会处理一段逻辑,只不过线程之间切换得比较快,看着像多个线程”同时”运行罢了。多核CPU上的多线程才是真正的多线程,它能让你的多段逻辑同时工作,多线程,可以真正发挥出多核CPU的优势来,达到充分利用CPU的目的。 (2)防止阻塞 从程序运行效率的角度来看,单核CPU不但不会发挥出多线程的优势,反而会因为在单核CPU上运行多线程导致线程上下文的切换,而降低程序整体的效率。但是单核CPU我们还是要应用多线程,就是为了防止阻塞。试想,如果单核CPU使用单线程,那么只要这个线程阻塞了,比方说远程读取某个数据吧,对端迟迟未返回又没有设置超时时间,那么你的整个程序在数据返回回来之前就停止运行了。多线程可以防止这个问题,多条线程同时运行,哪怕一条线程的代码执行读取数据阻塞,也不会影响其它任务的执行。 (3)便于建模 这是另外一个没有这么明显的优点了。假设有一个大的任务A,单线程编程,那么就要考虑很多,建立整个程序模型比较麻烦。但是如果把这个大的任务A分解成几个小任务,任务B、任务C、任务D,分别建立程序模型,并通过多线程分别运行这几个任务,那就简单很多了。 2、创建线程的方式 比较常见的一个问题了,一般就是两种: (1)继承Thread类 (2)实现Runnable接口 至于哪个好,不用说肯定是后者好,因为实现接口的方式比继承类的方式更灵活,也能减少程序之间的耦合度,面向接口编程也是设计模式6大原则的核心。 3、start()方法和run()方法的区别 只有调用了start()方法,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行。如果只是调用run()方法,那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码。 4、Runnable接口和Callable接口的区别 有点深的问题了,也看出一个Java程序员学习知识的广度。 Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。 这其实是很有用的一个特性,因为多线程相比单线程更难、更复杂的一个重要原因就是因为多线程充满着未知性,某条线程是否执行了?某条线程执行了多久?某条线程执行的时候我们期望的数据是否已经赋值完毕?无法得知,我们能做的只是等待这条多线程的任务执行完毕而已。而Callable+Future/FutureTask却可以获取多线程运行的结果,可以在等待时间太长没获取到需要的数据的情况下取消该线程的任务,真的是非常有用。 5、CyclicBarrier和CountDownLatch的区别 两个看上去有点像的类,都在java.util.concurrent下,都可以用来表示代码运行到某个点上,二者的区别在于: (1)CyclicBarrier的某个线程运行到某个点上之后,该线程即停止运行,直到所有的线程都到达了这个点,所有线程才重新运行;CountDownLatch则不是,某线程运行到某个点上之后,只是给某个数值-1而已,该线程继续运行 (2)CyclicBarrier只能唤起一个任务,CountDownLatch可以唤起多个任务 (3)CyclicBarrier可重用,CountDownLatch不可重用,计数值为0该CountDownLatch就不可再用了 6、volatile关键字的作用 一个非常重要的问题,是每个学习、应用多线程的Java程序员都必须掌握的。理解volatile关键字的作用的前提是要理解Java内存模型,这里就不讲Java内存模型了,可以参见第31点,volatile关键字的作用主要有两个: (1)多线程主要围绕可见性和原子性两个特性而展开,使用volatile关键字修饰的变量,保证了其在多线程之间的可见性,即每次读取到volatile变量,一定是最新的数据 (2)代码底层执行不像我们看到的高级语言—-Java程序这么简单,它的执行是Java代码–>字节码–>根据字节码执行对应的C/C++代码–>C/C++代码被编译成汇编语言–>和硬件电路交互,现实中,为了获取更好的性能JVM可能会对指令进行重排序,多线程下可能会出现一些意想不到的问题。使用volatile则会对禁止语义重排序,当然这也一定程度上降低了代码执行效率 从实践角度而言,volatile的一个重要作用就是和CAS结合,保证了原子性,详细的可以参见java.util.concurrent.atomic包下的类,比如AtomicInteger。 7、什么是线程安全 又是一个理论的问题,各式各样的答案有很多,我给出一个个人认为解释地最好的:如果你的代码在多线程下执行和在单线程下执行永远都能获得一样的结果,那么你的代码就是线程安全的。 这个问题有值得一提的地方,就是线程安全也是有几个级别的: (1)不可变 像String、Integer、Long这些,都是final类型的类,任何一个线程都改变不了它们的值,要改变除非新创建一个,因此这些不可变对象不需要任何同步手段就可以直接在多线程环境下使用 (2)绝对线程安全 不管运行时环境如何,调用者都不需要额外的同步措施。要做到这一点通常需要付出许多额外的代价,Java中标注自己是线程安全的类,实际上绝大多数都不是线程安全的,不过绝对线程安全的类,Java中也有,比方说CopyOnWriteArrayList、CopyOnWriteArraySet (3)相对线程安全 相对线程安全也就是我们通常意义上所说的线程安全,像Vector这种,add、remove方法都是原子操作,不会被打断,但也仅限于此,如果有个线程在遍历某个Vector、有个线程同时在add这个Vector,99%的情况下都会出现ConcurrentModificationException,也就是fail-fast机制。 (4)线程非安全 这个就没什么好说的了,ArrayList、LinkedList、HashMap等都是线程非安全的类 8、Java中如何获取到线程dump文件 死循环、死锁、阻塞、页面打开慢等问题,打线程dump是最好的解决问题的途径。所谓线程dump也就是线程堆栈,获取到线程堆栈有两步: (1)获取到线程的pid,可以通过使用jps命令,在Linux环境下还可以使用ps -ef | grep java (2)打印线程堆栈,可以通过使用jstack pid命令,在Linux环境下还可以使用kill -3 pid […]

Spring全局异常处理

[异常处理方式一. @ExceptionHandler] [异常处理方式二. 实现HandlerExceptionResolver接口] [异常处理方式三. @ControllerAdvice+@ExceptionHandler] [三种方式比较说明] 问题描述: 假如对异常不进行处理? 假如SpringMvc我们不对异常进行任何处理, 界面上显示的是这样的. 异常处理的方式有三种: 一. Controller层面上异常处理 @ExceptionHandler 说明:针对可能出问题的Controller,新增注解方法@ExceptionHandler. 注意事项: ​ 1. 一个Controller下多个@ExceptionHandler上的异常类型不能出现一样的,否则运行时抛异常. Ambiguous @ExceptionHandler method mapped for; ​ 2. @ExceptionHandler下方法返回值类型支持多种,常见的ModelAndView,@ResponseBody注解标注,ResponseEntity等类型都OK. 原理说明: 代码片段位于:org.springframework.web.servlet.DispatcherServlet#doDispatch 执行@RequestMapping方法抛出异常后,Spring框架 try-catch的方法捕获异常, 正常逻辑发不发生异常都会走processDispatchResult流程 ,区别在于异常的参数是否为null . 代码片段位于:org.springframework.web.servlet.DispatcherServlet#processDispatchResult 如果@RequestMapping方法抛出异常,拦截器的postHandle方法不执行,进入 processDispatchResult,判断入参 dispatchException,不为null , 代表发生异常,调用processHandlerException处理, 代码片段位于:org.springframework.web.servlet.DispatcherServlet#processHandlerException this当前对象指dispatchServlet,handlerExceptionResolvers可以看到有三个HandlerExceptionResolver, 这三个是帮我们注册的. 遍历有序集合handlerExceptionResolvers,调用接口的resolveException方法. 记录注册的第一个 HandlerExceptionResolver : ExceptionHandlerExceptionResolver, 继承关系如下面所示. 代码片段位于:org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#resolveException AbstractHandlerExceptionResolver 和 AbstractHandlerMethodExceptionResolver名字看起来非常相似. 这里AbstractHandlerExceptionResolver […]

一份超详细的Linux命令及Java问题排查工具单

一份超详细的Java问题排查工具单 转自:云栖社区,作者:红魔七号 前言 平时的工作中经常碰到很多疑难问题的处理,在解决问题的同时,有一些工具起到了相当大的作用,在此书写下来,一是作为笔记,可以让自己后续忘记了可快速翻阅,二是分享,希望看到此文的同学们可以拿出自己日常觉得帮助很大的工具,大家一起进步。闲话不多说,开搞。 Linux命令类 tail 最常用的tail -f grep awk 1.基础命令 2.匹配 3.内建变量 NR:NR表示从awk开始执行后,按照记录分隔符读取的数据次数,默认的记录分隔符为换行符,因此默认的就是读取的数据行数,NR可以理解为Number of Record的缩写。 FNR:在awk处理多个输入文件的时候,在处理完第一个文件后,NR并不会从1开始,而是继续累加,因此就出现了FNR,每当处理一个新文件的时候,FNR就从1开始计数,FNR可以理解为File Number of Record。 NF: NF表示目前的记录被分割的字段的数目,NF可以理解为Number of Field。 find pgm 批量查询vm-shopbase满足条件的日志 tsar tsar是咱公司自己的采集工具。很好用, 将历史收集到的数据持久化在磁盘上,所以我们快速来查询历史的系统数据。当然实时的应用情况也是可以查询的啦。大部分机器上都有安装。 top top除了看一些基本信息之外,剩下的就是配合来查询vm的各种问题了 获得线程10进制转16进制后jstack去抓看这个线程到底在干啥 其他 排查利器 btrace (第三方) 首当其冲的要说的是btrace。真是生产环境&预发的排查问题大杀器。简介什么的就不说了。直接上代码干 1.查看当前谁调用了ArrayList的add方法,同时只打印当前ArrayList的size大于500的线程调用栈 2.监控当前服务方法被调用时返回的值以及请求的参数 其他功能集团的一些工具或多或少都有,就不说了。感兴趣的请移步。https://github.com/btraceio/btrace 注意:经过观察,1.3.9的release输出不稳定,要多触发几次才能看到正确的结果正则表达式匹配trace类时范围一定要控制,否则极有可能出现跑满CPU导致应用卡死的情况由于是字节码注入的原理,想要应用恢复到正常情况,需要重启应用。 Greys(第三方) Greys是@杜琨的大作吧。说几个挺棒的功能(部分功能和btrace重合): sc -df xxx: 输出当前类的详情,包括源码位置和classloader结构 trace class method: 相当喜欢这个功能! 很早前可以早JProfiler看到这个功能。打印出当前方法调用的耗时情况,细分到每个方法。对排查方法性能时很有帮助,比如我之前这篇就是使用了trace命令来的:http://www.atatech.org/articles/52947。 其他功能部分和btrace重合,可以选用,感兴趣的请移步。http://www.atatech.org/articles/26247 另外相关联的是arthas,他是基于Greys的,感兴趣的再移步http://mw.alibaba-inc.com/products/arthas/docs/middleware-container/arthas.wiki/home.html?spm=a1z9z.8109794.header.32.1lsoMc […]

MySQL InnoDB 的加锁分析

​转:https://www.xttblog.com/?p=4926 背景 ​​ MySQL/InnoDB的加锁分析,一直是一个比较困难的话题。我在工作过程中,经常会有同事咨询这方面的问题。同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题。本文,准备就MySQL/InnoDB的加锁问题,展开较为深入的分析与讨论,主要是介绍一种思路,运用此思路,拿到任何一条SQL语句,都能完整的分析出这条语句会加什么锁?会有什么样的使用风险?甚至是分析线上的一个死锁场景,了解死锁产生的原因。​​ 注:MySQL是一个支持插件式存储引擎的数据库系统。本文下面的所有介绍,都是基于InnoDB存储引擎,其他引擎的表现,会有较大的区别。 ​​ 多版本并发控制 MVCC ​​ MySQL InnoDB 存储引擎,实现的是基于多版本的并发控制协议 MVCC (Multi-Version Concurrency Control) ,与 MVCC 相对的,是基于锁的并发控制,Lock-Based Concurrency Control。MVCC 最大的好处,相信也是耳熟能详:读不加锁,读写不冲突。在读多写少的 OLTP 应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,这也是为什么现阶段,几乎所有的 RDBMS,都支持了 MVCC。​​ 在 MVCC 并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。​​ 在一个支持 MVCC 并发控制的系统中,哪些读操作是快照读?哪些操作又是当前读呢?以 MySQL InnoDB 为例,看下面的例子:​​ 快照读:简单的select操作,属于快照读,不加锁。(当然,也有例外,下面会分析)​​ ​​ 当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。  ​​ select * from table where ? lock in share mode; select * […]

JVM调优及内存问题排查

Linux使用jstat命令查看jvm的GC情况 http://www.open-open.com/lib/view/open1390916852007.html http://www.aiuxian.com/article/p-2032660.html http://blog.csdn.net/u011202334/article/details/51498108 Options,选项,我们一般使用 -gcutil 查看gc情况 vmid,VM的进程号,即当前运行的java进程号 interval,间隔时间,单位为秒或者毫秒 count,打印次数,如果缺省则打印无数次 通常运行命令如下: jstat -gc 12538 5000 即会每5秒一次显示进程号为12538的java进成的GC情况, 显示内容如下图: jstat -gcutil 28363 1s jstat -gccause pid 1 每格1毫秒输出结果jstat -gccause pid 2000 每格2秒输出结果 说明 显示内容说明如下(部分结果是通过其他其他参数显示的,暂不说明): S0C:年轻代中第一个survivor(幸存区)的容量 (字节) S1C:年轻代中第二个survivor(幸存区)的容量 (字节) S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节) S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节) EC:年轻代中Eden(伊甸园)的容量 (字节) EU:年轻代中Eden(伊甸园)目前已使用空间 (字节) OC:Old代的容量 (字节) OU:Old代目前已使用空间 (字节) PC:Perm(持久代)的容量 (字节) PU:Perm(持久代)目前已使用空间 (字节) YGC:从应用程序启动到采样时年轻代中gc次数 YGCT:从应用程序启动到采样时年轻代中gc所用时间(s) FGC:从应用程序启动到采样时old代(全gc)gc次数 […]

lWoHvYe 无悔,专一