Java问题答案集合

有链接的都是引用别人的知识点。
总结下HashMap在1.7和1.8之间的变化:
1.7采用数组+单链表,1.8在单链表超过一定长度后改成红黑树存储
1.7扩容时需要重新计算哈希值和索引位置,1.8并不重新计算哈希值,巧妙地采用和扩容后容量进行&操作来计算新的索引位置。
1.7插入元素到单链表中采用头插入法,1.8采用的是尾插入法。

因为重写的equal()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高,那么hashCode()既然效率这么高为什么还要equal()呢?
因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出:

1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。

2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。

3.Iterator中和核心的方法next(),hasnext(),remove(),都是依赖当前位置,如果这些集合直接实现Iterator,则必须包括当前迭代位置的指针。当集合在方法间进行传递的时候,由于当前位置不可知,所以next()之后的值,也不可知。而当实现Iterable则不然,每次调用都返回一个从头开始的迭代器,各个迭代器之间互不影响。

4.jdk动态代理需要目标类实现接口 因为InvocationHandler里面有一段获取接口的代码,cglib不需要实现接口

6.线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情

	ReentrantLock获取锁定与三种方式:
	a)  lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
	b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
	c)tryLock(long timeout,TimeUnit unit),   如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,
		在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
	d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,
		或者当前线程被别的线程中断

	synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,
		JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

	在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,
		Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

在 JDK 中,主要由以下类来实现 Java 反射机制,这些类都位于 java.lang.reflect 包中:
Class 类:代表一个类。
Field 类:代表类的成员变量(成员变量也称为类的属性)。
Method 类:代表类的方法。
Constructor 类:代表类的构造方法。
Array 类:提供了动态创建数组,以及访问数组的元素的静态方法。

下面给出几个例子看看 Reflection API 的实际运用:

一、通过 Class 类获取成员变量、成员方法、接口、超类、构造方法等

在 java.lang.Object 类中定义了 getClass() 方法,因此对于任意一个 Java 对象,都可以通过此方法获得对象的类型。 Class 类是 Reflection API 中的核心类,它有以下方法
getName() :获得类的完整名字。
getFields() :获得类的 public 类型的属性。
getDeclaredFields() :获得类的所有属性。
getMethods() :获得类的 public 类型的方法。
getDeclaredMethods() :获得类的所有方法。
getMethod(String name, Class[] parameterTypes) :获得类的特定方法, name 参数指定方法的名字, parameterTypes 参数指定方法的参数类型。
getConstructors() :获得类的 public 类型的构造方法。
getConstructor(Class[] parameterTypes) :获得类的特定构造方法, parameterTypes 参数指定构造方法的参数类型。
newInstance() :通过类的不带参数的构造方法创建这个类的一个对象。
编写Java反射程序的步骤:
 1)必须首先获取一个类的Class对象
  例如:

 Class c1 = Test.class;
  Class c2 = Class.forName(“com.reflection.Test”);
  Class c3 = new Test().getClass();

2)然后分别调用Class对象中的方法来获取一个类的属性/方法/构造方法的结构
  注意:如果要能够正常的获取类中方法/属性/构造方法应该重点掌握如下的反射类
  Field
  Constructor
  Method

spring有六种事务五种隔离级别

第一类:整型 byte short int long
第二类:浮点型 float double
第三类:逻辑型 boolean(它只有两个值可取true false)
第四类:字符型 char

final修饰类中的方法
作用:可以被继承,但继承后不能被重写。
final修饰类
作用:类不可以被继承。
final修饰基本类型时候值不变,引用类型表示地址不变,就是new的时候那个是地址不能重新赋值
final修饰属性你懂的

prepareStatement是预编译的,先把这个SQL提交到数据库中进行预处理,然后将其放到缓存里面,下次发现有相同的就不用编译了,
执行效率高,有语法提示方便检查,参数是动态的,防止sql注入因为语法检查
select * from tbName = ‘zck’ and passwd = ‘’ or ‘1’ = ‘1’;
statement就不是预编译,而且需要手动检查语法错误,属于硬编码

HashMap允许将null作为一个entry的key或者value,而Hashtable不允许
put方法
HashMap会对null值key进行特殊处理,总是放到table[0]位置
put过程是先计算hash然后通过hash与table.length取摸计算index值,然后将key放到table[index]位置,当table[index]已存在其它元素时,会在table[index]位置形成一个链表,
将新添加的元素放在table[index],原来的元素通过Entry的next进行链接,这样以链表形式解决hash冲突问题,当元素数量达到临界值(capactiyfactor)时,
则进行扩容,是table数组长度变为table.length
2
get方法
同样当key为null时会进行特殊处理,在table[0]的链表上查找key为null的元素
get的过程是先计算hash然后通过hash与table.length取摸计算index值,然后遍历table[index]上的链表,
直到找到key,然后返回
HashMap和Hashtable的底层实现都是数组+链表结构实现的
添加、删除、获取元素时都是先计算hash,根据hash和table.length计算index也就是table数组的下标,
然后进行相应操作

索引大多数基于B树

Servlet线程安全问题主要是由实例变量造成的,因此在Servlet中应避免使用实例变量。
如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径。

HashTable是一个线程安全的类,它使用synchronized来锁住整张Hash表来实现线程安全,
即每次锁住整张表让线程独占。ConcurrentHashMap允许多个修改操作并发进行,
其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。
ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的Hashtable,
它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,
这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,
否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,
但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。
这可以确保不会出现死锁,因为获得锁的顺序是固定的

① ThreadLocal ② synchronized( ) ③ wait() 与 notify() ④ volatile
ThreadLocal
ThreadLocal 保证不同线程拥有不同实例,相同线程一定拥有相同的实例,即为每一个使用该变量的线程提供
一个该变量值的副本,每一个线程都可以独立改变自己的副本,而不是与其它线程的副本冲突。
优势:提供了线程安全的共享对象
与其它同步机制的区别:同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信;
而 ThreadLocal 是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源,这样当然不需要多个线程进行同步了。
volatile
volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,
当成员变量发生变化时,强迫线程将变化值回写到共享内存。
优势:这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
缘由:Java 语言规范中指出,为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,
而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。
而 volatile 关键字就是提示 VM :对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用技巧:在两个或者更多的线程访问的成员变量上使用 volatile 。
当要访问的变量已在 synchronized 代码块中,或者为常量时,不必使用。
线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),
线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步,
因此存在A和B不一致的情况。volatile就是用来避免这种情况的。
volatile告诉jvm,它所修饰的变量不保留拷贝,直接访问主内存中的
(读操作多时使用较好;线程间需要通信,本条做不到)
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。
这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,
但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile
变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值;该变量没有包含在具有其他变量的不变式中。
sleep() vs wait()
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,
但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,
只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
(如果变量被声明为volatile,在每次访问时都会和主存一致;如果变量在同步方法或者同步块中被访问,
当在方法或者块的入口处获得锁以及方法或者块退出时释放锁时变量被同步。)

http://www.cnblogs.com/zxf330301/p/5634987.html

http://blog.csdn.net/chenssy/article/details/26668941

http://www.yjbys.com/news/202750.html

客户程序要先得到具体容器角色,然后再通过具体容器角色得到具体迭代器角色
Iterator it=new ArrayList.iterator();

  1. 访问一个容器对象的内容而无需暴露它的内部表示。
  2. 支持对容器对象的多种遍历。
  3. 为遍历不同的容器结构提供一个统一的接口(多态迭代)。

使用new关键字 } → 调用了构造函数
使用Class类的newInstance方法 } → 调用了构造函数
使用Constructor类的newInstance方法 } → 调用了构造函数
使用clone方法 } → 没有调用构造函数
使用反序列化 } → 没有调用构造函数
Employee emp2 = (Employee) Class.forName(“com.Employee”).newInstance();
或者
Employee emp2 = Employee.class.newInstance();

Constructor constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();

使用clone方法,我们需要先实现Cloneable接口并实现其定义的clone方法
Employee emp4 = (Employee) emp3.clone();

程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,
通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,
从而只有class文件被载入到了内存之后,
才能被其它class所引用。所以ClassLoader就是用来动态加载class文件到内存当中用的。

Bootstrap ClassLoader:称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,
如:rt.jar、resources.jar、charsets.jar等
Extension ClassLoader:称为扩展类加载器,负责加载Java的扩展类库,
默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
App ClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。
因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代
java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,
因为String已经在启动时就被引导类加载器(Bootstrcp ClassLoader)加载,
所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。

1、request对象 客户端请求,此请求会包含来自GET/POST请求的参数通过它才能了 解到客户的需求,然后做出响应。
2、response对象 响应客户请求的有关信息
3、session对象 它指的是客户端与服务器的一次会话,从客户端连到服务器的一个 WebApplication开始,直到客户端与服务 器断开连接为止。
4、out对象 它是JspWriter类的实例,是向客户端输出内容常用的对象
5、page对象 它是指向当前JSP页面本身,有点象类中的this指针,它是 java.lang.Object类的实例
6、application对象 它实现了用户间数据的共享,可存放全局变量。它开始于服务器的启动,直到服务器的关闭
7、exception对象 它是一个例外对象,当一个页面在运行过程中发生了例外,就产生这个对象。
8、pageContext对象 它提供了对JSP页面内所有的对象及名字空间的访问
9、config对象 它是在一个Servlet初始化时,JSP引擎向它传递信息用的

js有个函数 isNaN(val)//如果是数字则返回 false

有XMLDOM解析、SAX解析、StAX解析
XMLDOM:(XMLDocumentObjectModel)处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问;
SAX:(SimpleAPIforXML)不同于DOM,SAX是事件驱动型的XML解析方式。它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问;
StAX:(StreamingAPIforXML)与其他方法的区别就在于应用程序能够把XML作为一个事件流来处理,无论从性能还是可用性上都优于其他方法;

thread.getState()

http://blog.chinaunix.net/uid-26602509-id-3306451.html

四中类型8种基本类型数据 byte short int long float double char Boolean不是对象,他们有对应的包装类型
equals比较的字符串对象的值
==在字符串比较是地址,而基本类型比较的就是值了
、静态变量只能由静态方法调用,一般是类调用或者对象,经常用类
privatr 只对本类可以见 protced 本包和子类 默认 对本包可见
运行时候自动向上转。
变量的值会变化,不确定具体的值,所以整型默认使用int类型,小数是double进行存储
重写方法必须满足下列条件
(1) 子类的方法的名称及参数必须和所覆盖的方法相同
(2) 子类的方法返回类型必须和所覆盖的方法相同
(3) 子类方法不能缩小所覆盖方法的访问权限
(4) 子类方法不能抛出比所覆盖方法更多的异常

重载方法必须满足下列条件
被重载的方法必须改变参数列表(参数个数或类型或顺序不一样);
被重载的方法可以改变返回类型;
被重载的方法可以改变访问修饰符;
被重载的方法可以声明新的或更广的检查异常;
方法能够在同一个类中或者在一个子类中被重载。
无法以返回值类型作为重载函数的区分标准。
Integer数据直接赋值,-128 127之间,直接从缓冲池里面拿数据不开辟空间
集合只能存放引用类型
迭代器依赖于集合存在
并发需改异常;
迭代器遍历集合修改集合的时候,集合变了迭代器不知道
List:有序 可重复
ArrayList:基于数组结构的,线程不安全
Vevtor:基于数组结构的,线程安全
LinkedList:基于链表的,线程不安全
Set:无序 不可重复
HashSet:基于hash表,元素唯一性依赖于hashCode()和equals()
LinkedHashSet:基于链表和哈希表,链表保证元素有序,哈希表保证元素唯一
TreeSet:基于红黑树,元素排序自然排序,比较器排序,唯一性,根据返回的值是否是0来决定

finally前面如果有return的话,当执行到return的时候,看见了finally的时候,
去执行了finally,然后return结束,return的结果是他的值,不是执行finally后的值

构造方法不能递归调用。编译不能通过。递归容易导致内存溢出。
追加可以使用构造方法是true那个
字符流=字节流+编码

堆:
堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时
动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
栈:
栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
栈中主要存放一些基本类 型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。
String是一个特殊的包装类数据。可以用:
String str = new String(“abc”);
String str = “abc”;
两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,
并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

并发:同一个时间点(物理上的)
并行:时间内(逻辑上的)
java程序运行原理;java命令启动了jvm。相当于启动了一个进程,该进程创建主线程去调用main方法
jvm启动是多线程的,还有垃圾回收线程呀,不然内存溢出怎么办。

方式一
继承Thread
run和start的区别:run:直接调用的时候是普通方法,单线程
start:先启动一个线程然后jvm再去调用run,
同一个线程不能调用两次 new my().start.再来一次start就错了。可以new my1来调用start
方式二
实现Runable接口

sleep和wait
sleep:必须指定时间,调用之后不释放锁的哦。
wait:参数随便,调用之后锁就释放了。

线程安全类:Vector 、Hashtable、
不安全的类:ArrayList、HashMap、Linkedlist
支持排序的类:TreeSet
ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。
在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

  • 1:String,StringBuffer,StringBuilder的区别?
  • A:String是内容不可变的,而StringBuffer,StringBuilder都是内容可变的。
  • B:StringBuffer是同步的,数据安全,效率低;StringBuilder是不同步的,数据不安全,效率高
  • 2:StringBuffer和数组的区别?
  • 二者都可以看出是一个容器,装其他的数据。
  • 但是呢,StringBuffer的数据最终是一个字符串数据。
  • 而数组可以放置多种数据,但必须是同一种数据类型的。
  • 3:形式参数问题
  • String作为参数传递
  • StringBuffer作为参数传递
  • 形式参数:
  •  基本类型:形式参数的改变不影响实际参数
    
  •  引用类型:形式参数的改变直接影响实际参数
    
  • 注意:
  •  String作为参数传递,效果和基本类型作为参数传递是一样的。
    

A. 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
B. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
C. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

spring管理了datasource,与数据库进行访问时候,获取的connection受spring管理,进行事务的时候,是同一个connection,如果发生了异常进行回滚否则提交事务。

吞吐量:这里的吞吐量是指应用程序所花费的时间和系统总运行时间的比值。我们可以按照这个公式来计算 GC 的吞吐量:系统总运行时间 = 应用程序耗时 +GC 耗时。如果系统运行了 100 分钟,GC 耗时 1 分钟,则系统吞吐量为 99%。GC 的吞吐量一般不能低于 95%。

停顿时间:指垃圾收集器正在运行时,应用程序的暂停时间。对于串行回收器而言,停顿时间可能会比较长;而使用并发回收器,由于垃圾收集器和应用程序交替运行,程序的停顿时间就会变短,但其效率很可能不如独占垃圾收集器,系统的吞吐量也很可能会降低。

垃圾回收频率:多久发生一次指垃圾回收呢?通常垃圾回收的频率越低越好,增大堆内存空间可以有效降低垃圾回收发生的频率,但同时也意味着堆积的回收对象越多,最终也会增加回收时的停顿时间。所以我们只要适当地增大堆内存空间,保证正常的垃圾回收频率即可。
1.所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

2.新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。

3.当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收

4.新生代发生的GC也叫做Minor GC(复制算法 防止碎片化 两个 survivor)0,MinorGC发生频率比较高(不一定等Eden区满了才触发)

程序计数器:当前线程所执行的字节码的行号指示器,用于记录正在执行的虚拟机字节指令地址,线程私有。

Java虚拟栈:存放基本数据类型、对象的引用、方法出口等,线程私有。

Native方法栈:和虚拟栈相似,只不过它服务于Native方法,线程私有。

Java堆:java内存最大的一块,所有对象实例、数组都存放在java堆,GC回收的地方,线程共享。

方法区:存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码数据等。(即永久带),回收目标主要是常量池的回收和类型的卸载,各线程共享
栈溢出:
栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类型,对象引用类型
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常,方法递归调用产生这种结果。
如果Java虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内存去完成扩展,或者在新建立线程的时候没有足够的内存去创建对应的虚拟机栈,那么Java虚拟机将抛出一个OutOfMemory 异常。(线程启动过多)
参数 -Xss 去调整JVM栈的大小
为什么要分为Eden和Survivor?为什么要设置两个Survivor区
如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC.老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多,所以需要分为Eden和Survivor。
Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。
设置两个Survivor区最大的好处就是解决了碎片化,刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生)
元空间内存管理
元空间的内存管理由元空间虚拟机来完成。先前,对于类的元数据我们需要不同的垃圾回收器进行处理,现在只需要执行元空间虚拟机的C++代码即可完成。在元空间中,类和其元数据的生命周期和其对应的类加载器是相同的。话句话说,只要类加载器存活,其加载的类的元数据也是存活的,因而不会被回收掉。
准确的来说,每一个类加载器的存储区域都称作一个元空间,所有的元空间合在一起就是我们一直说的元空间。当一个类加载器被垃圾回收器标记为不再存活,其对应的元空间会被回收。在元空间的回收过程中没有重定位和压缩等操作。但是元空间内的元数据会进行扫描来确定Java引用。
context-param -> listener -> filter -> servlet

首先,Kafka 通过把 message 顺序写入磁盘来提高写入和读取效率。
其次,kafka 利用操作系统的页存储来提高写入效率
再次,Kafka 也通过 zero copy 技术来提高了数据的写入效率。
最后,Kafka 的 message 传输支持压缩技术。

CAS需要有3个操作数:内存地址V(volatile),旧的预期值A,即将要更新的目标值B。

CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。
在这里插入图片描述

CAS虽然很高效,但是它也存在三大问题,这里也简单说一下:

  1. ABA问题。CAS需要在操作值的时候检查内存值是否发生变化,没有发生变化才会更新内存值。但是如果内存值原来是A,后来变成了B,然后又变成了A,那么CAS进行检查时会发现值没有发生变化,但是实际上是有变化的。ABA问题的解决思路就是在变量前面添加版本号,每次变量更新的时候都把版本号加一,这样变化过程就从“A-B-A”变成了“1A-2B-3A”。
    JDK从1.5开始提供了AtomicStampedReference类来解决ABA问题,具体操作封装在compareAndSet()中。compareAndSet()首先检查当前引用和当前标志与预期引用和预期标志是否相等,如果都相等,则以原子方式将引用值和标志的值设置为给定的更新值。
  2. 循环时间长开销大。CAS操作如果长时间不成功,会导致其一直自旋,给CPU带来非常大的开销。
  3. 只能保证一个共享变量的原子操作。对一个共享变量执行操作时,CAS能够保证原子操作,但是对多个共享变量操作时,CAS是无法保证操作的原子性的。
    Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里来进行CAS操作。
    CAP原则 C- 数据一致性;A-服务可用性;P-服务对网络分区故障的容错性
    eureka (AP)
    zk (CP)
    Secondary NameNode
    fsimage - 它是在NameNode启动时对整个文件系统的快照
    edit logs - 它是在NameNode启动后,对文件系统的改动序列
    NameNode重启时,edit logs才会合并到fsimage文件中,
    从而得到一个文件系统的最新快照,但是因log过大,重启过慢或者回复过慢
    定时到NameNode去获取edit logs,并更新到fsimage上
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值