1.什么是Java内存模型?
Java程序是要运行在Java虚拟机上面的,Java内存模型(Java Memory Model,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致的机制和规范。2.MySQL的事务隔离级别? MySQL的事务隔离级别其实跟spring的事务隔离级别一样,都是1、Read Uncommitted(读取未提交内容,也被称之为脏读),2、Read Committed(读取提交内容),3、Repeatable Read(可重读,MySQL的默认事务隔离级别),4、Serializable(可串行化)3.Spring的原理? spring的核心是IOC和AOP,IOC是依赖注入和控制反转,注入方式可以分为set注入,构造器注入,接口注入。IOC就是一个容器,负责实例化、定位、配置应用程序中的对象及遍历这些对象间的依赖。IOC的思想是:Spring来管理这些,对象只用处理本身业务关系。控制反转:获得依赖的方式反转了,原本有程序员自己创建的对象交给了Spring来管理。4.重写equals为何要重写hashCode?(==比较的是地址,equals比较的对象内容) 判断两个对象是否相等,比较的是hashcode,如果你重载了equals,而hashcode没做出改变,那么可能造成两个对象明明是相等的,而hashcode却不一样,造成无法认定两个对象是否相等。5.Object中的几个方法 1.hashCode():获取用户的hash值,用于检索 2.clone():创建并返回此对象的副本 3.equals(Object obj) :指示一些其他对象是否等于此。 4.getClass() :返回此 Object的运行时类。 5.toString() :返回对象的字符串表示形式。 6.wait():导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。 7.notify()和notifyAll():唤醒正在等待对象监视器的单个/所有线程6.动态代理的两种方式,以及区别 代理方式分为JDK动态代理和cglib动态代理 JDK动态代理只能对实现了接口的类生成代理,而不能针对类 cglib动态代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。7.浅谈线程池,在线程池创建一个线程的过程 线程池:创建线程需要花费时间,如果等任务来了再去创建,效率难免有点低,从JDK1.5开始,Java API提供了Executor框架可以创建不同的线程池。 corePoolSize:核心线程数,能够同时执行的任务数量 maximumPoolSize:最大线程数,表明线程中最多能够创建的线程数量 keepAliveTime:空闲的线程保留时间 TimeUnit:空闲线程的保留时间单位 workQueue:阻塞等待线程的队列 threadFactory:创建线程的工厂 handler:当任务数超过了maximumPoolSize时,对任务的处理策略,默认策略时拒绝添加 执行过程:当线程数小于corePoolSize时,每添加一个任务,就会立即开启线程执行;当corePoolSize满了的时候,后面添加的任务将放入缓冲队列workQueue等待;当workQueue满的时候,看是否超过了maximumPoolSize线程数,如果超过,则拒绝执行,如果没有,则创建线程立即执行。8.悲观锁和乐观锁和乐观锁实现之CAS操作 悲观锁:总是假设最坏的情况,每次拿数据的时候都会认为别人会修改数据,所以每次拿数据时都会上锁,这样别人拿数据时候就会进入阻塞状态,Java中的synchronized就是悲观锁。关系型数据库中的行锁,读锁,写锁都是悲观锁。 乐观锁:每次拿数据时都认为别人不会修改,不会上锁,但在更新的时候会判断一下在此期间别人有没有更新这个数据,乐观锁用于多读的类型,可以提高吞吐量。 CAS(Compare-And-Swap,比较和替换),其具有三个操作数:内存地址V,旧的预期值A,新的预期值B。更新变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。CAS值的替换是原子性的。CAS是乐观锁技术,当多个线程使用CAS去更新一个变量的时候,如果存在竞争,则没有获取资源的进程不会立即挂起,而是采用让线程进入到一种忙循环中,等过一段时间看能否获取锁,如果超出时间则挂起。缺点就是存在ABA问题(我内存对象从A变成B在变成A,CAS会当成没有变化,实际有变化),循环时间长开销大(一直和预期不对的情况下,会一直循环)9.线程的状态都有哪些? 新建状态(new,线程还没有开始执行),就绪状态(Runnable,一个新建的线程并不会自动运行,需要调用线程的start()方法),运行状态(Running,开始执行run()方法),阻塞状态(blocked,运行过程中,可能由于各种原因进入阻塞状态),死亡状态(dead,run方法自然退出,线程执行完毕,或者捕获了一个异常终止了run方法) 阻塞状态的原因: 1.线程通过调用sleep方法进入睡眠状态 2.线程试图得到一个锁,而这个锁正被其他线程持有 3.线程正在等待某个触发条件10.sleep和wait的区别: sleep()方法属于thread类的,而wait()方法属于Object类的;sleep()方法导致了程序暂停执行的特定时间,让出CPU给其他线程,但是他的监控状态一直保持,当到达指定的时间又自动回到运行状态,调用sleep()方法的过程中,线程不会释放对象锁;而当调用了wait()方法的时候,线程会放弃对象锁,进入到此对象的等待锁池,只有针对了此对象调用notify()或者notifyAll()方法后本线程才进入到对象锁池准备。如果线程重新获得对象的锁就可以进入就绪状态11.Java线程中的堆和栈 每个线程都会有自己的栈内存,用于存储本地变量、方法参数和栈调用,一个线程中存储的变量对其他线程时不可见的。而堆是所有线程共享的一片公共内存区域,对象都在堆内创建,为了提高效率,线程会从堆内存中缓存到自己的栈,如果多个线程使用该变量就可能引发问题,这时volatile变量就可以发挥作用,它要求线程从主存中读取变量的值。12.三个线程如何保证顺序执行 用Thread.join()方法13.怎么检测一个线程是否拥有锁? java.long.Thread中有一个方法就holdslocak()方法,返回值为Boolean类型 Thread类中的yield方法可以暂停当前正在执行的线程对象,让其他有相同优先级的线程执行,让当前线程由“运行状态”进入到“就绪状态”,14.如何避免死锁 多线程的死锁:是指两个或者两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的情况。死锁必定满足以下条件: 1.互斥条件:一个资源每次只能被一个进程使用 2.请求和保持条件:一个进程因请求资源而被阻塞时,对已获得的资源保持不放 3.不剥夺条件:进程已获得资源,在未使用完之前,不能强行剥夺 4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系 最简单的解决方式:阻塞循环等待条件,以一定的顺序来操作15.什么时阻塞式方式 阻塞式方式是指程序会一直等待该方法完成期间不可做其他事情。16. java中ConcurrentHashMap的并发度是什么? ConcurrentHashMap会把实际map划分若干部分来实现它的可扩展性和线程安全,这种划分是使用并发度获得的,它是ConcurrentHashMap类构造函数的一个可选参数,默认值为16,这样可以在多线程情况下就能避免争用锁。