零散

ThreadLocal

  • ThreadLocal(线程变量副本) Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量。
  • 采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。
  • ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本ThreadLocal在Spring中发挥着巨大的作用,在管理Request作用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。 Spring中绝大部分Bean都可以声明成Singleton作用域,采用ThreadLocal进行封装,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。

Java内存模型:

Java虚拟机规范中将Java运行时数据分为六种。

  • 1.程序计数器:是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器,互不影响,该区域为“线程私有”。
  • 2.Java虚拟机栈:线程私有的,与线程生命周期相同,用于存储局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型,还有对象的引用。
  • 3.本地方法栈:跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务。
  • 4.Java堆:所有线程共享的一块内存区域,对象实例几乎都在这分配内存。 -线程共享
  • 5.方法区:各个线程共享的区域,储存虚拟机加载的类信息,常量,静态变量,编译后的代码。
  • 6.运行时常量池:代表运行时每个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用。

你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?

在什么时候:

  • 1.新生代有一个Eden区和两个survivor区,首先将对象放入Eden区,如果空间不足就向其中的一个survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC,将存活的对象放入另一个survivor区中,然后清空Eden和之前的那个survivor区的内存。在某次GC过程中,如果发现仍然又放不下的对象,就将这些对象放入老年代内存里去。
  • 2.大对象以及长期存活的对象直接进入老年区。
  • 3.当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,如果这些马上要到老年区的老年对象的大小超过了老年区的剩余大小,那么执行一次Full GC以尽可能地获得老年区的空间。 对什么东西:从GC Roots搜索不到,而且经过一次标记清理之后仍没有复活的对象。

做什么: 新生代:复制清理; 老年代:标记-清除和标记-压缩算法; 永久代:存放Java中的类和加载类的类加载器本身。

GC Roots都有哪些:

Synchronized 与Lock

Synchronized 与Lock都是可重入锁,同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁。

  • Synchronized是悲观锁机制,独占锁。
  • Locks.ReentrantLock是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。

ReentrantLock适用场景

  • 1.某个线程在等待一个锁的控制权的这段时间需要中断
  • 2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程,锁可以绑定多个条件。
  • 3.具有公平锁功能,每个到来的线程都将排队等候。

StringBuffer和StringBuilder

StringBuffer是线程安全的,每次操作字符串,String会生成一个新的对象,而StringBuffer不会;StringBuilder是非线程安全的

fail-fast

java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。 例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件

Volatile和Synchronized四个不同点

  • 粒度不同,前者锁对象和类,后者针对变量
  • syn阻塞,volatile线程不阻塞
  • syn保证三大特性,volatile不保证原子性
  • syn编译器优化,volatile不优化

volatile具备两种特性

  • 保证此变量对所有线程的可见性,指一条线程修改了这个变量的值,新值对于其他线程来说是可见的,但并不是多线程安全的
  • 禁止指令重排序优化。

Volatile如何保证内存可见性

  • 1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。
  • 2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量

同步,异步,阻塞,非阻塞

  • 同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。
  • 异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己任务完成了就算完成了,被依赖的任务是否完成会通知回来。(异步的特点就是通知)。 打电话和发短信来比喻同步和异步操作。
  • 阻塞:CPU停下来等一个慢的操作完成以后,才会接着完成其他的工作。
  • 非阻塞:非阻塞就是在这个慢的执行时,CPU去做其他工作,等这个慢的完成后,CPU才会接着完成后续的操作。 非阻塞会造成线程切换增加,增加CPU的使用时间能不能补偿系统的切换成本需要考虑。

CAS(Compare And Swap)

  • 无锁算法: CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。
  • CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

线程池的作用

在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程

  • 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 第三:提高线程的可管理性。

常用线程池:

ExecutorService 是主要的实现类,其中常用的有

  • Executors.newSingleThreadPool(),
  • newFixedThreadPool(),
  • newcachedTheadPool(),
  • newScheduledThreadPool()。

类加载器工作机制

  • 装载:将Java二进制代码导入jvm中,生成Class文件。
  • 连接:a)校验:检查载入Class文件数据的正确性 b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用
  • 初始化:对类的静态变量,静态方法和静态代码块执行初始化工作。

双亲委派模型

类加载器收到类加载请求,首先将请求委派给父类加载器完成 用户自定义加载器->应用程序加载器->扩展类加载器->启动类加载器。

缓存

  • Memcahed缓存: 数据结构:key,value对 使用方法:get,put等方法
  • Redis数据结构: String—字符串(key-value 类型) Hash—字典(hashmap) Redis的哈希结构可以使你像在数据库中更新一个属性一样只修改某一项属性值 List—列表 实现消息队列 Set—集合 利用唯一性 Sorted Set—有序集合 可以进行排序 可以实现数据持久化

索引

B+,B-,全文索引 Mysql的索引是一个数据结构,旨在使数据库高效的查找数据。 常用的数据结构是B+Tree,每个叶子节点不但存放了索引键的相关信息还增加了指向相邻叶子节点的指针,这样就形成了带有顺序访问指针的B+Tree,做这个优化的目的是提高不同区间访问的性能。

什么时候使用索引

  • 经常出现在group by,order by和distinc关键字后面的字段
  • 经常与其他表进行连接的表,在连接字段上应该建立索引
  • 经常出现在Where子句中的字段
  • 经常出现用作查询选择的字段

Spring IOC (控制反转,依赖注入)

  • Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,构造注入和接口注入。
  • 在Spring中,那些组成应用的主体及由Spring IOC容器所管理的对象被称之为Bean。
  • Spring的IOC容器通过反射的机制实例化Bean并建立Bean之间的依赖关系。
  • 简单地讲,Bean就是由Spring IOC容器初始化、装配及被管理的对象。
  • 获取Bean对象的过程,首先通过Resource加载配置文件并启动IOC容器,
  • 然后通过getBean方法获取bean对象,就可以调用他的方法。

Spring Bean的作用域

  • singleton
  • prototype
  • request
  • session
  • global session

Spring的事物的传播

  • PROPAGATION_REQUIRED 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
  • PROPAGATION_SUPPORTS 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
  • PROPAGATION_MANDATORY 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
  • PROPAGATION_REQUIRED_NEW 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
  • PROPAGATION_NOT_SUPPORTED 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
  • PROPAGATION_NEVER 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
  • PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务

事物的隔离性

  • 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
  • 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。《更新记录》
  • 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。《新增和删除》

数据库的事物的隔离性

  • ISOLATION_DEFAULT 使用后端数据库默认的隔离级别
  • ISOLATION_READ_UNCOMMITTED 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • ISOLATION_READ_COMMITTED 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • ISOLATION_REPEATABLE_READ 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
  • ISOLATION_SERIALIZABLE 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

子类能重写父类的构造函数吗

子类 不可以 重写 父类 的 构造方法,因为构造方法是父类特有的,子类根本继承不了父类的构造函数,所以子类不可以重写父类的构造方法。但是可以使用关键字 super 调用父类的构造方法。

results for ""

    No results matching ""