1.@component主要用于注册到类上,告诉spring容器要去注册创建一个类,并且扫描路径自动装配到spring;
在@component 中 注入无法生效 可以使用PostConstruct,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。
2.@bean 用在方法上,返回一个实例对象,告诉Spring,然后在Spring容器中注册成一个bean,通常方法体中包含了最终产生bean实例的逻辑。
主要用于第三方库中的类需要装配到Spring容器,因为无法在第三方库中加@Component注解,只能通过@Bean来实现。
https://www.cnblogs.com/xuwujing/p/10933082.html
1.ResponseStatus ,自定义类extends RuntimeException状态异常处理 value 和reason 一个是值 一个是返回异常信息
2.@ExceptionHandler应用在被@controller和@ControllerAdvice注解的controller中的方法上。为了在controller内部处理异常,我们使用这个注解标注方法,如果需要的话也可以同时使用@ExceptionHandle和@ResponseStatus。定义异常处理方法时,同时也定义view名称,异常对象名称等。
3.使用@ControllerAdvice做全局异常处理
为了处理全局异常,spring提供了@ControllerAdvice来注解定义的handler类,类中处理方法用@ExceptionHandler注解。
集成 runtimeException
4.配置SimpleMappingExceptionResolver处理异常 new这个异常类
5.自定义HandlerExceptionResolver类处理异常 实现这个异常类
1.User selectUser(String name,String area);
select * from user_user_t where user_name = #{0} and user_area=#{1}
其中,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
2.User selectUser(Map paramMap);
select * from user_user_t where user_name = #{userName,jdbcType=VARCHAR} and user_area=#{userArea,jdbcType=VARCHAR}
3.User selectUser(@Param("userName")String name,@Param("userArea")String area);
select * from user_user_t where user_name = #{userName,jdbcType=VARCHAR} and user_area=#{userArea,jdbcType=VARCHAR}
1.limit(1) 取第一条
2.order by column desc limit 1
jQuery是使用选择器($)选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容:$("lable").val();
,它还是依赖DOM元素的值。
Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。
@ControllerAdvice
@RestController
@service
@requestMapping
@requestBody
@exceptionHandler
等等
hashtable 无序 线程安全 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。Hashtable的任何操作都会把整个表锁住,是阻塞的。好处是总能获取最实时的更新,比如说线程A调用putAll写入大量数据,期间线程B调用get,线程B就会被阻塞,直到线程A完成putAll,因此线程B肯定能获取到线程A写入的完整数据。坏处是所有调用都要排队,效率较低。
hashmap 无序 JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突).JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间 ,可实现快速存储和检索,但其缺点是其包含的元素是无序的,这导致它在存在大量迭代的情况下表现不佳。
treemap 有序 红黑树(自平衡的排序二叉树) 能便捷的实现对其内部元素的各种排序,但其一般性能比前两种map差。
linkedHashMap 有序 LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。保留了HashMap的优势,且其包含的元素是有序的。它在有大量迭代的情况下表现更好。映射减少了HashMap排序中的混乱,且不会导致TreeMap的性能损失。
ConcurrentHashMap 无序 ConcurrentHashMap 是设计为非阻塞的。在更新时会局部锁住某部分数据,但不会把整个表都锁住。同步读取操作则是完全非阻塞的。好处是在保证合理的同步前提下,效率很高。坏处是严格来说读取操作不能保证反映最近的更新。例如线程A调用putAll写入大量数据,期间线程B调用get,则只能get到目前为止已经顺利插入的部分数据。
应该根据具体的应用场景选择合适的HashMap。
1.互斥条件:一个资源只能被一个线程使用。
2.请求和保持条件:当一个线程去获取另外资源陷入等待时,不释放自己所拥有的的资源
3.不剥夺条件:当资源被该线程使用时,不能被另外一个线程剥夺,直到该线程释放该资源
4.等待:当线程获取资源时,不想陷入等待状态,陷入死循环。
1.重试机制:在catch里捕获 进行count++ 从而判断 调用几次不在调用(还有其他的重试机制)
2.配置消息队列:由于内网访问外网速度慢,所以采用消息队列 将组成的数据由生产者放进消息队列,在由消费者进行获取到外网取到的数据进行消费拼装。
3.@scheduled 注解进行 定时查询天气 从而发给用户。
4.在获取外网数据慢的时候,由串行变成采用异步的方式去获取数据。
HashMap 最常用的 map集合 无序,只有一个KEY可以为null 值可以有多个null, 底层实现是用 数组 链表和红黑树。 加载因子是 0.75 加载因子 = 填入表中的元素个数 / 散列表的长度
加载因子越大,填满的元素越多,空间利用率越高,但发生冲突的机会变大了;
加载因子越小,填满的元素越少,冲突发生的机会减小,但空间浪费了更多了,而且还会提高扩容rehash操作的次数。
冲突的机会越大,说明需要查找的数据还需要通过另一个途径查找,这样查找的成本就越高。因此,必须在“冲突的机会”与“空间利用率”之间,寻找一种平衡与折衷。
根据泊松分布原理 选择0.75 将空间利用率和 hash碰撞概率 达到一个平衡。
初始化大小 为 16 当 插入长度>0.75*长度 就会发生 resize() 扩容 变成 2倍。 所以 初始化 hashmap时 建议长度 直接定好。
即 Map map = new HashMap(list.size()/0.75); 这样可以避免 map 进行扩容 浪费时间。
HashTable 线程安全 但是不推荐使用。 内部加入 synchronize 效率比较低现在在多线程环境下 使用 ConcurrentHashMap 比较多一点
ConcurrentHashMap 现在在多线程环境下使用它 线程安全的 采用 cas和Synchronize 进行加锁 底层采用 数组 链表和 红黑树
static class Node implements Map.Entry {
final int hash;
final K key;
volatile V val;
volatile Node next;
}
Value和next都是使用的volatile关键字进行了修饰,以确保线程安全。
为什么这里会用volatile进行修饰,我在其他博客找到了答案。主要有两个用处:
1、令这个被修饰的变量的更新具有可见性,一旦该变量遭到了修改,其他线程立马就会知道,立马放弃自己在自己工作内存中持有的该变量值,转而重新去主内存中获取到最新的该变量值。
2、产生了内存屏障,这里volatile可以保证CPU在执行代码时保证,所有被volatile中被修饰的之前的一定在之前被执行,也就是所谓的“指令重排序”。
TreeMap 有序的,不安全的。 输出时 采用key由小到大的排序进行 输出 达到一个排序的效果
LinkedHashMap 有序 底层链表 排序 它的有序主要体现在先进先出FIFIO上 LinkedHashMap主要依靠双向链表和hash表来实现的。
weakHashMap
首先,weakHashMap它是一个“弱键”,它的Key值和Value都可以是null,而且其Map中如果这个Key值指向的对象没被使用,此时触发了GC,该对象就会被回收掉的。其原理主要是使用的WeakReference和ReferenceQueue实现的,其key就是weakReference,而ReferenceQueue中保存了被回收的 Key-Value。
如果当其中一个Key-Value不再使用被回收时,就将其加入ReferenceQueue队列中。当下次再次调用该WeakHashMap时,就会去更新该map,比如ReferenceQueue中的key-value,将其中包含的key-value全部删除掉。这就是所谓的“自动删除”。
hashmap在创建过程中 一定要给一个初始值, list.size()/0.75 这样可以很大程度的避免 过于频繁的扩容导致浪费时间,
key 尽量使用 String 定义, 因为 String 是 final 类型的 当第一次定义 以后他会有缓存,这样在下次put 时候会减少比较时间。 更快速的定位 插入
HashTable HashTable的get/put方法都被synchronized关键字修饰,说明它们是方法级别阻塞的,它们占用共享资源锁,所以导致同时只能一个线程操作get或者put,而且get/put操作不能同时执行,所以这种同步的集合效率非常低,一般不建议使用这个集合。
ConcurrentHashMap 这个也是最推荐使用的线程安全的Map,也是实现方式最复杂的一个集合,每个版本的实现方式也不一样,在jdk8之前是使用分段加锁的一个方式,分成16个桶,每次只加锁其中一个桶,而在jdk8又加入了红黑树和CAS算法来实现。
SynchronizedMap private Map
其他博客: https://zhuanlan.zhihu.com/p/52563959 、https://www.jianshu.com/p/e2054351bd95、https://juejin.im/post/5cf4d520f265da1b6a347ed1
大体为两种 :
1.原生语义上的实现 synchronized (jvm层面的) 非公平,悲观,独享,互斥,可重入的重量级锁
2. java.util.concurrent 包 (JUC)下的两个
ReentrantLock,它是一个:默认非公平但可实现公平的,悲观,独享,互斥,可重入,重量级锁。
ReentrantReadWriteLocK,它是一个,默认非公平但可实现公平的,悲观,写独享,读共享,读写,可重入,重量级锁。
在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;
ReentrantLock 是一个独占/排他锁。
特性
ReentrantLock构造函数
提供了是否公平锁的初始化:
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
类型 |
描述 |
|
---|---|---|
共享(读锁) |
可被多个线程所持有,其他用户可以并发读取数据。如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。 |
ReentrantReadWriteLock里的读锁 |
独享(排他锁,写锁) |
一次只能被一个线程所持有。如果事务T对数据A加上排它锁后,则其他事务不能再对A加任何类型的锁。获得排它锁的事务即能读数据又能修改数据。 |
synchronized、ReentrantLock、ReentrantReadWriteLock里的写锁 |
共享锁的获取方法为acquireShared,源码为
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
当返回值为大于等于0的时候方法结束说明获得成功获取锁,否则,表明获取同步状态失败即所引用的线程获取锁失败,会执行doAcquireShared方法.
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
简单来说 addWaiter(Node mode) 方法做了以下事情:
创建基于当前线程的独占式类型的节点; 利用 CAS 原子操作,将节点加入队尾。
1.作用于实例方法,当前实例加锁,进入同步代码前要获得当前实例的锁;
2.作用于静态方法,当前类加锁,进去同步代码前要获得当前类对象的锁;
3.作用于代码块,这需要指定加锁的对象,对所给的指定对象加锁,进入同步代码前要获得指定对象的锁。
参考 : https://www.jianshu.com/p/27f5935cafd8
参考:https://thinkwon.blog.csdn.net/article/details/104863992
互斥条件:线程(进程)对于所分配到的资源具有排它性,即一个资源只能被一个线程(进程)占用,直到被该线程(进程)释放
请求与保持条件:一个线程(进程)因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
不剥夺条件:线程(进程)已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
循环等待条件:当发生死锁时,所等待的线程(进程)必定会形成一个环路(类似于死循环),造成永久阻塞
破坏任何一个条件都可以解除死锁。
防止死锁可以采用以下的方法:
尽量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
尽量使用 Java. util. concurrent 并发类代替自己手写锁。
尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
尽量减少同步的代码块。
8. 原子数据对象的原理?
java.util.concurrent包(JUC)底下的(重入锁) reentrantlock
参考:https://www.jianshu.com/p/dde297897eee
private Lock lock = new ReentrantLock(true);
public Condition washCondition = lock.newCondition();
需要借助于Condition接口与newCondition() 方法,线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活。
volatile 可以保证可见性但是不能保证原子性,禁止指令重排,提供happens-before 特性 保证一个线程的修改对于其他线程也是可见的。volatile 修饰变量, 当变量发生变化会直接更新到主内存。 用于多线程环境下对于共享变量的修饰 单次读或者单次写
volatile 会保证写操作一定会发生在读操作之前,确保先行关系。
java中可以创建 volatile 数组,但是其指向的是数组的引用,当引用指向的数组,发生改变时,volatile 会起到作用,但是多线程同时修改数组的元素,volatile 就不起作用了。
volatile 并不能保证其原子性。多线程下要对变量进行加锁保护,但是对 long 和double 可以保证其原子性,jvm底层操作是这样定义的。
volatile 修饰符可以用在单例模式中,private static volatile Singleton instance = null;
也会和 cas(compare和 swap) 一起使用 在 concurrenthashmap中的 node节点的 next变量上就是用 volatile修饰的,用来保证原子性。
volatile 不会造成线程的阻塞,volatile标记的变量不会被编译器优化
内存屏障:在它的赋值完成之前,就不用会调用读操作。
ThreadLocal是线程的内部存储类,可以在指定线程内存储数据。只有指定线程可以得到存储数据。
每个线程都有一个ThreadLocalMap的实例对象,并且通过ThreadLocal管理ThreadLocalMap。
ThreadLocal.ThreadLocalMap threadLocals = null;
每个新线程都会实例化为一个ThreadLocalMap并且赋值给成员变量ThreadLocals,使用时若已经存在threadLocals则直接使用已经存在的对象。
使用:参考:https://blog.csdn.net/Mrs_chens/article/details/90694392?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase
在其第一个demo中 控制台输出的demo 线程名字有重复的 说明线程 之间变量共享,但是使用threadlocal之后就不会有这种情况发生。
就是 ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用(相同线程数据共享),也就是变量在线程间隔离(不同的线程数据隔离)而在方法或类间共享的场景。
参考文档:https://www.jianshu.com/p/ead491db9749
order by 进行排序是 如果有相同字段的值,会出现 随机返回的情况,导致分页出现问题,解决的办法就是
order by Acolumn,id limit 10, 在排序时候在加上一个 不重复字段,这样保证其排序 分页 的准确性。