String、StringBuffer与StringBuilder之间区别
  String:在java中字符串属于java对象,java提供了string类来创建和操作字符串。但是值得注意的是string属于字符串常量,值是不会变的。
    这就导致了每次对string的操作都会生成新的string对象。这样不仅效率低下,还比较浪费内存空间。所以为了解决这一问题,就有了stringBuffer和stringBuilder;
  StringBuffer:字符串变量 线程安全的。可以多次操作不会产生新的未使用对象
  stringBuilder:字符串变量 非线程安全的。可以多次操作不会产生新的未使用对象
  但是在速度方面,stringBuilder > stringBuffer > String
  所以多数情况下使用stringBuilder,但是如果是程序要求线程安全的情况下就必须使用StringBuffer
  总结:
    如果要操作少量数据则使用String
    多线程字符串缓冲区下操作大量数据用StringBuffer
    单线程字符串缓冲区下操作大量数据用StringBuilder

fail-fast vs fail-save
  同步修改/并发修改:当一个或多个线程正在遍历一个集合collection,此时另一个线程修改了集合的内容(增加、删除或修改),这就是并发修改/同步修改

  fail-fast机制:当一个线程在遍历一个集合时,当集合结构被修改,会抛出concurrent modification exception
  fail-fast在两种情况下抛出concurrent modification exception
    1、单线程下,在遍历它的过程修改了结构,注意:remove()方法会让expectModcount 和modcount相等,所以不会抛异常。
    2、多线程下,当一个线程在遍历集合,而另一个线程对该集合结构进行了修改。
  fail-safe机制:对任何集合的修改都会在复制的集合上进行修改,因此不会抛出concurrent modification excption
  fail-safe机制有两个问题;
    1、需要复制集合,产生大量无效对象,开销大
    2、无法保证读取到的数据是否为目前原数据结构中的数据

happens-before:
  如果两个操作之间存在happens-before关系,那么前一个操作的结果就会对后面一个操作可见。(如果一个操作的结果对另一个操作可见,那么他们之间存在happens-before.)
  happens-before规则:
    1、程序次序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。
    2、监视器锁规则:对一个监视器锁的解锁,happens-before于随后对这个监视器锁的加锁。
    3、volatile变量规则:对于一个volatile域的写,happens-before于任意后续对这个volatile域的读。
    4、传递性:如果A happens-before B,B happens-before C ,那么 A happens-before C。
    5、start规则:如果线程A 执行操作ThreadB.start()【启动线程B】,那么A 线程的ThreadB.start()操作happens-before于线程B的任意操作
    6、join规则:如果线程A 执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于ThreadB.join操作成功返回。

volatile vs synchronized
  java多线程有三大特性:原子性、可见性、有序性
      原子性:是指线程的多个操作是一个整体,不能被分割。要么就不执行,要么就全部执行,中间不能被打断。
      可见性:是指线程之间的可见性。就是一个线程修改后,其他线程立马能够知道。
      有序性:为了提高执行效率,java的编译器和处理器可以对指令进行重新排序,重新排序会影响多线程并发的正确性,有序性就是保证不进行重新排序。
    volatile关键字的作用就是保证可见性和有序性,但不保证原子性。如果一个共享变量被volatile修饰,那么当有一个线程修改了这个共享变量后,其他线程也立马进行修改;
  volatile同时能禁止指令重新排序,在指令重排序优化时,在volatile变量之前的指令不能在volatile之后执行,反之同理。
  synchronized关键字提供了同步锁的概念,被synchronized修饰的代码可以防止被多个线程同时执行,因为synchronized保证了在同一时刻只能有一个线程执行同步代码块,
    所以执行同步代码块的操作相当于单线程。那么线程的三大特性都能保证了。
  volatile和synchronized的区别:
    1、volatile只能用在变量,范围较小。而synchronized则可以用在变量、方法。类、同步代码块等,范围较大。
    2、volatile只能保证可见性与有序性,不能保证原子性。而synchronized三大特性都可以。
    3、volatile不会造成线程阻塞,而synchronized会造成线程阻塞。

request.getParameter()、request.getInputStream()、request.getReader():

  request.getParameter()、request.getInputStream()、request.getReader()这三个方法都是从request对象得到提交的数据,但各有不同;

  request.getParameter():form的一个关键属性enctype=application/x- www-form-urlencoded,这也是默认的编码方式。编码后的结果通常是
    field1=value1&field2=value2...等。
    例:name=aaa&pwd=bbb;
    这应该属于最常用的获取提交数据,但弊端是对于传输较大块的二进制数据显得力不从心。

  request.getInputStream()、request.getReader(): form的编码方式为: "multipart/form-data"
    浏览器可以很容易将表单内的数据和文件放在一起发送。这种编码方式先定义好一个不可能在数据中出现的字符串作为 分界符,然后用它将各
    个数据段分开,而对于每个数据段都对应着 HTML 页面表单中的一个 Input 区,包括一个 content-disposition 属性,说明了这个数据段的一些
    信息,如果这个数据段的内容是一个文件,还会有 Content-Type 属性,然后就是数据本身,如果以这种方式提交数据就要用
    request.getInputStream()或request.getReader()得到 提交的数据,用 request.getParameter()是得不到提交的数据的。

  值得注意的是:request.getParameter()、request.getInputStream()、request.getReader()三个方法是有冲突的,因为流只能被读一次。

 

 

java gc:
为什么要了解GC和内存分配:在真实的项目中,会时不时发生内存溢出、内存泄漏的问题,这是大多数情况下不可避免的,掌握GC知识一方面我们可以快速排查定位JVM问题,
另一方面也可以帮助我们在java应用发布之前合理地对jvm进行调优,提高应用的执行效率、可靠性和健壮性。

堆是java JVM进行垃圾回收的主要场所,次要场所为方法区。

java中将堆内存分为3部分:新生代、老生代、永久代;而新生代又分为:Eden、From Survivor【S0】、To Survivor【S1】;其中,Eden区分配的内存较大,其他的两个区较小。
每次使用Eden和From Survivor。java虚拟机进行垃圾回收的时候,将Eden和S0里面还存活的对象进行一次性的复制到S1空间,直到其他两个区垃圾回收完成。当S1上空间不够时,需要其他老年代的内存进行分配担保。如果老年代的空间也被占满时,来自新生代的对象再请求进入老生带时就会报OutOfMemory。
我们在程序里new出来的对象一般情况下都会存在Eden。老生代一般也放着大对象。
新生代中垃圾回收的频率高,速度也较快;就GC垃圾回收机制而言,java虚拟机模型中的方法区人们更倾向于称呼为:永久代,保存在永久代中的对象一般不会被回收。
其永久代进行垃圾回收的频率就较低,速度也较慢。永久代的垃圾收集主要回收废弃常量和无用类。
以String常量abc为例,当我们声明了此常量,那么它就会被放到运行时常量池中,如果在常量池中没有任何对象对abc进行引用,那么abc这个常量就算是废弃常量而被回收;
判断一个类是否“无用”,则需同时满足三个条件:

          (1)、该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例;

          (2)、加载该类的ClassLoader已经被回收

          (3)、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

虚拟机可以对满足上述3个条件的无用类进行回收,这里说的是可以回收而不是必然回收。

 

深入JVM对象引用:

https://blog.csdn.net/dd864140130/article/details/49885811 

【强引用】【软引用】【弱引用】【虚引用】

  (1)、强引用:普遍存在 类似Person person = new Person();如果一个对象具有强引用,则无论在什么情况下,GC都不会回收被引用的对象。当内存空间不足时,JVM宁可抛出OutOfMemoryError终止应用程序也不会回收具有强引用的对象。      

Person person = new Person();

 

  (2)、软引用:有用但非必须。当内存空间充足时不回收,当内存空间不足时回收。      

Person person = new Person();

SoftReference sr = new SoftReference(person);

 

  (3)、弱引用:用来描述非必须的对象。类似软引用,但比软引用更弱。弱引用具有更短的生命周期,当GC在扫描的过程中,如果发现弱引用对象,则立即回数。      

Person person=new Person();

WeakReference wr=new WeakReference(person);

 

  (4)、虚引用:相当于没有引用。虚引用意味着任何时候都有可能被回收。设置虚引用的目的在于当虚引用被GC回收时,能够收到一个系统通知(被用来跟踪GC回收活动)。虚引用和弱引用的区别在于虚引用在引用时必须和引用队列(ReferenceQuene)联合使用。     

ReferenceQueue queue=new ReferenceQueue();

PhantomReference pr=new PhantomReference(object.queue);

  通常我们将其ReferenceQueue翻译为引用队列,换言之就是存放引用的队列,保存的是Reference对象。其作用在于Reference对象所引用的对象被GC回收时,该Reference对象将会被加入引用队列中(ReferenceQueue)的队列末尾,这相当于是一种通知机制.当关联的引用队列中有数据的时候,意味着引用指向的堆内存中的对象被回收。通过这种方式,JVM允许我们在对象被销毁后,做一些我们自己想做的事情。JVM提供了一个ReferenceHandler线程,将引用加入到注册的引用队列中

 

JAVA数据库连接的方式:

在java中访问数据库,做数据库连接时,可以采用两种方式:

  一、使用java.sql API

    利用该jar包提供的各种接口和类直接访问数据库。

    Drivermanager(驱动管理类)、Connection(连接类)、Statement(静态语句)、Preparedstatement(动态语句)

  二、使用数据库连接池

    1> 连接池的种类:

      JNDI

      C3p0

      DBCP

      BoneCP

      其中,spring框架依赖的第三方使用了C3p0和dbcp两种方式。而BoneCP则号称是速度最快的数据库连接池。JNDI方式创建实现的DataSource是真正实现了                               java.sql.DataSource,其他三种都不是。

    2> 连接池解决的问题:

      当使用java.sql中提供的api创建数据库连接时,需要耗费很大的资源。要进行用户名密码数据库验证等,既耗费时间又耗费资源。如果在实际操作中,如果每次需要访问数据库的时候,都进行数据库连接,那么势必会造成性能低下;同时,如果用户忘记了释放数据库连接,会导致资源浪费等。而数据库连接池就是解决该问题的:通过管理连接池中的多个连接对象,实现connection重复利用。从而大大提高了数据库连接方面的性能。

    3> 连接池的功能:

      负责创建、管理、释放、分配数据库连接

 

redis:

  简介:是一个key-value存储系统。存储的value类型包括:string、集合、链表、哈希类型。这些数据类型都支持pop/push、add/remove、取交集,并集、差集以及其他操作。并且这些操作都是原子性的。在此基础上,Redis支持与多种不同方式的排序。为保证效率,数据保存于内存中。Redis会定期把更新的数据写入磁盘或者把修改操作写入追加的记录文件。并在此基础上实现主从同步(master-slave)。

  一个高性能的key-value数据库

  Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以使关联其他从服务器的主服务器。这使得Redis可以进行单层树复制

  redis提供五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)和zset(sorted set有序集合)。

posted on 2019-02-19 11:18  村头老树下听风  阅读(173)  评论(0编辑  收藏  举报