java进阶

集合:
List分为arrayList和LinkedList,arrayList的底层是数组结构,因为使用角标,查询快,linkedList底部为双向链表结构,插入删除非常快适合插入删除频繁的场景,查询比较慢,因为它一个一个去比较。线程安全集合有Vector内部方法都使用sychonized关键字修饰,还可以使用
Collections.synchronizedList
Vector只能在尾部进行插入和删除操作,效率低
Map的底层结构为数组加链表(jdk1.7)jdk1.8后就是数组加链表,如果链表超过8位就转为红黑树,当红黑树节点小于6时又会转为链表先比较hashcode再比较值
hashMap几个重要的参数
1.默认hash桶的数量为16个,最大的桶容量为2的30次方,负载因子(loadfactor,默认0.75),负载因子有个奇特的效果,表示当当前容量大于(size/)时,将进行hashmap的扩容,扩容一般为扩容为原来的两倍,主要数据结构即为数组+链表。在hashmap中的主要表现形式为一个table,类型为Entry<K,V>[] table
为了解决hash碰撞,并不是直接使用key的hashcode,而是使用扰动函数来重新计算hash值,这样可以明显减少地减少碰撞。
也可使用扩容,当超过size的0.75倍时会扩容到原本的2倍。
  首先是一个Entry型的数组,Entry为hashmap的内部类:
为什么我们选择currentHashMap?那当然是因为HashTable是众多线程公用一把锁,而currentHashMap有分段锁,对不同的数据用不同的锁,当一个线程访问这一段数据时其他数据依然能被访问。
锁:
2.cas是什么?
cas是一种规范,像原子类就是他的实现,在竞争不激烈的情况下使用,优点是如果修改值不成功不会等待可以去做其他事,但是缺点是高并发对资源争夺激烈下性能差,有可能会出现aba的问题,这种可以加时间戳标志或者版本号来解决
sychconized是jvm的关键字不需要主动释放锁,Lock手动加手动释放,并且如果出现死锁的话,lock能够主动去中断,还可通过构造函数生成公平锁,但是不推荐使用,会让性能下降,sychconized在高并发情况下升级为重量级锁,是不可逆的,升级到重量级锁就回不去了
AQS就是AbstractQueuedSynchronizer,提供了获取锁释放锁的模板,里面包含state,如果state=0则通过cas修改,修改成功则用线程占有
JUC下我用过CountDownLactch(倒计数器,内部有内部类继承了AbstractQueuedSynchronize,用了state计数r),cyclicBarrier(一批线程在达到一个临界点时再往下走),semaphone(无论是内部锁synchronized还是重入锁ReentrantLock,一次只允许一个线程访问一个资源,而信号量却可以指定多个线程,同时访问同一个资源。)
3.线程池
ThreadPoolExecutor是实现4种线程池的构造方法
有个核心线程数和最大线程数
如果核心线程数满了,则会把线程存在阻塞队列里,如果最大线程数满了,则会调用拒绝策略,jdk有4种拒绝策略1.直接抛异常(默认)2.直接丢弃3.丢弃最早的4.主线程自己调用excutor去执行。
4.mysql调优,事务
sql调优的思路
索引有
1.普通索引
2.唯一索引
3.主键索引
4.组合索引
5.全文索引
建立索引,尽量选择where,order by,group by后面的字段,反向判断会让索引失效,notnull,notIn,不等于,以%开头的LIKE查询
MVCC多版本并发控制,4中隔离级别有:读未提交,读已提交,可重复读,序列化。
spring是怎么做到隔离级别的:
只比mysql多一个默认的隔离级别使用数据隔离级别
声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
spring的生命周期:
实例化,属性注入,执行初始化,使用,销毁
垃圾回收算法有哪些:
标记清除法(会产生内存碎片)
复制算法(把堆内存分为2块,把活动对象放一边,暴力的清除一边,缺点是内存支持量偏低)
标记整理算法(我的理解是让存活的对象都像一边移动,然后清除边界以外的内存)
分代收集算法
新生代对象存活率低,就采用复制算法;老年代存活率高,就用标记清除算法或者标记整理算法
垃圾回收器cms,g1
Spring IOC容器创建一个Bean实例时,可以为Bean指定实例的作用域,作用域包括singleton(单例模式)、prototype(原型模式)、request(HTTP请求)、session(会话)、global-session(全局会话)。
mybatis的#可以防止sql注入
Mybatis的二级缓存是指mapper映射文件一级缓存是session缓存。

一.java内存模型(在栈里运行的内存模型,栈放满了就会内存溢出)
1.java内存区域(逻辑上的,是按规范划分出来的结果)
方法区:存放静态信息,类信息,常量。(可实现数据共享)
堆区:存放实例化信息。(可实现数据共享)
栈区:存放引用类型地址,局部变量
本地方法栈:跟native相关
程序计数器:存放下一个指令地址
2.java的内存泄漏,内存的分配是由程序完成的,而内存的释放是有GC完成的,释放对象的根本原则就是该对象不再被引用。被引用却无用的对象就可以判定为Java中的内存泄漏,比如:

Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
    Object o=new Object();
    v.add(o);
    o=null; 
}

这时只是把o给释放,但是vector却没有被释放。
3.java内存模型(抽象的模型,规范,可实现数据共享)
线程有自己的工作内存,
如果修改共享数据会去主内存复制一份到工作内存,修改完后刷新到主内存。
如果修改私有数据,直接在工作空间修改。
4.并发编程三大特性:原子性,可见性,有序性
如果是局部变量有原子性,比如Z=z+1是把z复制到自己的工作空间进行+1然后刷新到主内存
二.synchronized的原理分析
每个对象都有monitor,监视器
当有线程占有这个对象时,monitor+1,释放时-1,只有monitor=0时才会获取这个对象控制权。
三.单列模式
饿汉式:static直接实列化一个对象,这种模式线程是安全的,一来就加载性能不好。
懒汉模式:用到再实例化,但是同步方法会影响性能,所以用同步代码块+双层校验,因为有可能指令重排,所以加valitle
四.CAS和AQS
Thread.join可以让多线程按照自己指定的顺序执行
CAS(无锁的)
原子类的实现原理就是CAS(准备修改的对象,期望这个对象是哪个值,修改值,修改完后的值)
CompareAndSet是一个native方法
适合冲突比较少的场景。
AQS(同步发生器,构建锁的规范)
并发工具包的使用:
类似于前端的awit,当一个结果需要在某一个线程执行完毕后得出时,用countDownLatch设置总量,然后每个线程执行完毕后-1,当为0时就返回结果,有2个核心方法,coutdown。await,是所有线程都执行完,自减
cyclicBarrier是线程中某一时刻暂停,等其他线程执行完毕后再一起执行,自加
new Semaphore(5);可以控制5个线程访问,资源有限共享
五.并发集合
非阻塞式集合:如果add和poll不能执行则报错
ConcurrentLinkDeque
阻塞式集合:如果add和poll不能执行则等待
LinkedBlockingDeque
六.线程池原理
通用构造方法:ThreadPoolExcutor
一个int有32位,1位存一个单元
让一个对象不销毁就一直引用它
七.模拟spring IOC
DI是IOC的一种实现
spring通过构造方法和set方法区注入
@AutoWired先以byType查找如果有2个以上再以byName查找
spring的生命周期的回调:
Bean实现InitinglizeBean接口
spring类中相互引用如果是多列就不行
@Lazy为spring的懒加载机制
@Configuration 中所有带 @Bean 注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例。
八.spring IOC
先在配置类加上
@EnableAspectJAutoProxy
再在类上加上@acpect定义切面类,再定义切点(去哪做),在定义通知(做些什么)
九:java的值传递和引用传弟是有争议的,我的理解是只要创建副本就是值传递,基本数据类型和包装类和string不会变


```java
 String a = "a";
          String b = a;
          b = "b";
        System.out.println(a);//a

        ArrayList<Integer> arr = new ArrayList();
        ArrayList<Integer> arr2 = arr;
        arr2.add(1);
        System.out.println(arr);//[1]

        Integer integer = new Integer(10);
        Integer integer2 = integer;
        integer2 = new Integer(5);
        System.out.println(integer);//5

        Boolean s = new Boolean(true);
        Boolean s2 = s;
        s2 = new Boolean(false);
        System.out.println(s);//true

十:调用wait(),notify()和notifyAll()的线程在调用这些方法前必须"拥有"对象的锁。当前的线程不是此对象锁的所有者,却调用该对象的notify(),notify(),wait()方法时抛出该异常。
再多问几个问题,为什么要加锁呢?因为只有加锁才能保证多线程交替有序执行,否则线程的执行是由操作系统随机调度的,那么执行顺序自然是乱序的。为什么要对同一个对象加锁呢?因为只有对同一对象加锁,才能保证访问该锁的两个线程之间相互通信(不同的对象调用notify不会唤醒处于wait状态的线程),否则即使线程已经获取到锁了,但可能会因为没轮到自己执行而一直处于wait状态。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值