Code Monkey home page Code Monkey logo

blog's People

Watchers

 avatar  avatar

blog's Issues

Mybatis学习笔记-1

Mybatis框架架构

mybatis-1
mybatis-2

Mybatis接口层(和数据库交互的方式)

两种方式:

  1. 传统的Mybatis提供的API接口
  2. Mapper接口
  • 传统的Mybatis提供的API
    传递Statement Id和查询参数给SqlSession对象,使用SqlSession对象完成和数据库的交互。
    mybatis-3
  • 使用Mapper接口
    MyBatis 将配置文件中的每一个 节点抽象为一个 Mapper 接口,而这个接口中声明的方法和跟 节点中的<select|update|delete|insert> 节点项对应,即<select|update|delete|insert> 节点的id值为Mapper 接口中的方法名称,parameterType 值表示Mapper 对应方法的入参类型,而resultMap 值则对应了Mapper 接口表示的返回值类型或者返回结果集的元素类型。
    mybatis-4

Mybatis数据处理层

完成2个功能:

  1. 通过传入参数构建动态SQL语句;
    2.SQL语句的执行以及封装查询结果集成List

框架支撑层

  • 事务管理机制
  • 连接池管理机制
  • 缓存机制
  • SQL语句的配置机制

引导层

引导层是配置和启动MyBatis 配置信息的方式。
MyBatis 提供两种方式来引导MyBatis :

  1. 基于XML配置文件的方式
  2. 基于Java API 的方式

Mybatis主要构件及其相互关系

  • SqlSession:表示和数据库交互的会话,完成必要数据库增删改查功能
  • Executor:负责SQL语句的生成和查询缓存的维护
  • StatementHandler:封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
  • ParameterHandler:负责对用户传递的参数转换成JDBC Statement 所需要的参数
  • ResultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
  • TypeHandler:负责java数据类型和jdbc数据类型之间的映射和转换
  • MapperStatement:MappedStatement维护了一条<select|update|delete|insert>节点的封装,
  • SqlSource:负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
  • BoundSql:表示动态生成的SQL语句以及相应的参数信息
  • Configuration:MyBatis所有的配置信息都维持在Configuration对象之中。

参考:
https://www.cnblogs.com/KingIceMou/p/7193769.html

Set集合

HashSet类

  1. HashSet是无序的。
  2. HashSet不是同步的,如果多个线程同时访问一个HashSet,则必须通过代码来保证其同步。
  3. 集合元素值可以是null。

HashSet判断两个元素相等的标准:两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。

TreeSet类

TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。

EnumSet类

  1. EnumSet不允许加入null元素。EnumSet中的所有元素都必须是指定枚举类型的枚举值。
  2. EnumSet类没有暴露任何构造器来创建该类的实例,程序应该通过它提供的类方法来创建EnumSet对象。

参考:
https://www.jianshu.com/p/9081017a2d67

Linux常用命令

打包、压缩

  1. tar
创建一个新tar文件 tar cvf archive_name.tar dirname/
解包tar文件 tar xvf archive_name.tar
查看tar文件 tar tvf archive_name.tar
  1. gzip
创建一个*.gz的压缩文件 gzip test.txt
解压*.gz文件 gzip -d test.txt.gz
显示压缩的比率 gzip -l *.gz
  1. bzip2
创建*.bz2压缩文件 bzip2 test.txt
解压*.bz2文件 bzip2 -d test.txt.bz2
  1. unzip
解压*.zip文件 unzip test.zip
查看*.zip文件的内容 unzip -l jasper.zip

文件搜索

  1. find
查找指定文件名的文件(忽略大小写) find 目录 -iname "MyProgram.c"
查找home目录下的所有空文件 find ~ -empty
  1. grep
在文件中查找字符串(忽略大小写) grep -i "the" demo_file
输出成功匹配的行,以及该行之后的三行 grep -A 3 -i "example" demo_text
在一个文件夹中递归查询包含指定字符串的文件 grep -r "ramesh" *
  1. ls
以易读的方式显示文件大小(显示为MB,GB...) ls -lh
以最后修改时间升序列出文件 ls -ltr
在文件名后面显示文件类型 ls -F

文本操作

  1. sed
当你将Dos系统中的文件复制到Unix/Linux后,这个文件每行都会以\r\n结尾,sed可以轻易将其转换为Unix格式的文件,使用\n结尾的文件 sed 's/.$//' filename
反转文件内容并输出 sed -n '1!G; h; p' filename
为非空行添加行号 sed '/./=' thegeekstuff.txt
  1. sort
以升序对文件内容排序 sort names.txt
以降序对文件内容排序 sort -r names.txt
以第三个字段对/etc/passwd的内容排序 sort -t: -k 3n /etc/passwd | more
  1. tail
命令默认显示文件最后的10行文本 tail filename.txt
-n选项指定要显示的行数 tail -n N filename.txt
-f选项进行实时查看 tail -f ./catalina.out

SSH登录

登录到远程主机 ssh -l jsmith remotehost.example.com
调试ssh客户端 ssh -v -l jsmith remotehost.example.com
显示ssh客户端版本 ssh -V

系统操作

显示文件系统的磁盘使用情况,默认情况下df -k将以字节为单位输出磁盘的使用量 df -k -h
kill用于终止一个进程 kill -9 7256
查看当前正在运行的所有进程 ps -ef | more
以树状结构显示当前正在运行的进程 ps -efH | more
查看和配置Linux系统的网络接口 ifconfig -a
使用up和down命令启动或停止某个接口 ifconfig eth0 up 或 ifconfig eth0 down
内核信息 uname -a
top命令会显示当前系统中占用资源最多的一些进程 top
显示某个特定用户的进程 top -u root
以其他单位输出内存使用量 free -g
查看所有内存的汇总 free -t
立即关机 shutdown -h now
10分钟后关机 shutdown -h +10
重启 shutdown -r now
重启期间强制进行系统检查 shutdown -Fr now

其他操作

比较的时候忽略空白字符 diff -w name_list.txt name_list_new.txt
输出跟字符串oracle匹配的环境变量 export | grep ORACLE
设置全局环境变量 export ORACLE_HOME=/u01/app/oracle/product/10.2.0
设置系统时间 date -s "10/04/2018 23:00:00"
修改了系统时间,需要同步硬件时间和系统时间 hwclock --systohc -utc
下载文件 wget http://example.com/xx.tar.gz
下载文件并指定文件名保存 wget -O a.tar.gz http://example.com/xx.tar.gz

HashMap类相关概念

HashMap类主要成员变量

  • transient size
    记录Map中KV对的个数
  • loadFactor
    加载因子,默认0.75f
  • int threshold
    临界值,当实际KV对个数超过threshold时,HashMap会扩容,threshold=容量*加载因子
  • capacity
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4
    容量,默认为1 << 4 //16

size和capacity

  • capacity表示最多可以装多少元素,size表示已经装了多少元素。
  • capacity默认容量为16,当用户通过构造函数指定了一个数字作为容量,Hash会选择大于该数字的第一个2的幂作为容量。

loadFactor和threshold

  • threshold:当HashMap的元素个数size超过临界值threshold时,HashMap会自动扩容。
  • loadFactor是装载因子,表示HashMap满的程度,默认值为0.75f,设置成0.75有一个好处,那就是0.75正好是3/4,而capacity又是2的幂。所以,两个数的乘积都是整数(capacity为2也同样)。

xmlns xmlns:xsi xsi:schemaLocation

xmlns是什么

官方概念,xmlns是xml namespace的缩写,是XML命名空间,xmlns属性可以在文档中定义一个或多个可供选择的命名空间。该属性可以放在文档内任何元素的开始标签中。该属性的值类似于URL,它定义了一个命名空间,浏览器会将此命名空间用于该属性所在元素内的所有内容。

xmlns作用

如果是XHTML文档,他就需要一个XML命名空间来规范它的语法。XHTML是用XML的语法来规范的HTML语言。这个标准位于属性值的网址。

xmlns:xsi

xmlns:xsi全名xml schema instance,表示使用xsi作为前缀的Namespace

xsi:schemaLocation

指具体用到的schema资源

参考:
https://www.cnblogs.com/zhao1949/p/5652167.html

IDEA常用设置

IDEA常用设置

  1. 右下角内存显示
    memory indicator

  2. IDEA启动时,项目选择设置
    chose

  3. 代码补全大小写设置(默认First letter)
    All

  4. 开启自动导包(默认关闭)
    auto-import

  5. Ctrl+鼠标滑轮改变字体大小
    font-size

  6. 显示行数和方法分隔
    lineNum&funcSeparators

  7. 文件名显示
    file-name

  8. 自动生成serialVersionUID
    serialVersionUID

  9. IDEA全局设置(File-->Other Setting-->Default Setting)
    编码设置
    encode
    maven设置
    maven

  10. 单行方法展开
    one-line-methods

String类创建对象

字面量和运行时常量池

在JVM运行时区域的方法区中,有一块区域是运行时常量池,主要用来存储编译期生成的各种字面量和符号引用。
Java代码被Javac编译之后,文件结构中包含一部分的Constant Pool。.class文件中的常量池部分的内容,会在运行期被运行时常量池(Run-time Constant Pool)加载进去。

new String创建对象分析

  1. 编译期:
    String str = new String("abc");
    符号引用str和字面量abc会在编译器被加入到class文件的常量池,然后在类加载阶段,这两个常量会进入常量池。但果需要加到字符串常量池中的字符串已经存在,那么就不需要再把字符串字面量加载进来了。
    若常量池中已经存在"abc",则直接引用,也就是此时只会创建一个对象,说的就是这个字符串字面量在字符串池中被创建的过程。
  2. 运行期:
    在运行期,new String("abc")执行的时候,要在Java堆中创建一个字符串对象,而这个对象所对应的字符串字面量是保存在字符串常量池中的。

intern方法

可以简单的理解为String s1 = "Hollis";和String s3 = new String("Hollis").intern();做的事情是一样的。

String s1 = "abc";
String s2 = new String("abc");
String s3 = new String("abc").intern();
System.out.println(s1 == s3);  //true

s1和s3都是字符串常量池中的字面量的引用,所以s1==s3
s2的引用是堆中的对象,所以s2!=s1

intern的用法

对于字符串的拼接,纯字面量和字面量的拼接,会把拼接结果作为常量保存到字符串。"ab"+"cd"
在字符串拼接中,有一个参数是非字面量,而是一个变量的话,整个拼接操作会被编译成StringBuilder.append,这种情况编译器是无法知道其确定值的。只有在运行期才能确定。str1+str2
对于那种可能经常使用的字符串,使用intern进行定义,每次JVM运行到这段代码的时候,就会直接把常量池中该字面值的引用返回,这样就可以减少大量字符串对象的创建了。

参考:
http://zhuanlan.51cto.com/art/201806/577095.htm

Maven坐标

Maven坐标

作用:用来唯一标识jar、war这些构件。
Maven坐标包括:groupIdartifactIdversionpackagingclassifier

  • groupId、artifactId、version必须
  • packaging可选(默认jar):定义打包方式
  • classifier不可直接定义,由附加的插件帮助生成

IDEA常用快捷键操作(Windows)

IDEA常用快捷键

快捷键 介绍
Ctrl + 代码补全(个人修改后)
Alt + 左右方向键 退回/前进到上一个操作的地方(个人修改)
Alt + F7 查找光标所在的方法 / 变量 / 类被调用的地方
Alt + Insert 代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等
Ctrl + Alt + L 格式化代码,可以对当前文件和整个包目录使用
Ctrl + Alt + B 在某个调用的方法名上使用会跳到具体的实现处,可以跳过接口
Ctrl + Alt + S 打开Settings面板
Ctrl + Alt + F7 显示使用的地方。寻找被该类或是变量被调用的地方,用弹出框的方式找出来

Spring web.xml文件(过滤器、监听器)

web.xml文件

web.xml(部署描述符文件)是Java web工程的一个配置文件,是在Servlet规范中定义的,用来初始化配置信息。主要用来配置:欢迎页(welcome-file-list)、servlet、filter、listener,启动加载级别等。
一个web工程可以没有web.xml文件。

web.xml配置

<?xml version="1.0" encoding="UTF-8"?>   
<!DOCTYPE web-app>  
<web-app version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
      
    <context-param>  
        <param-name>contextConfigLocation</param-name>  
        <param-value>classpath*:spring/applicationContext_*.xml</param-value>  
    </context-param>  
    <listener>  
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    </listener>  
      
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <session-config>  
        <session-timeout>20</session-timeout>  
    </session-config>  
    <servlet>  
        <display-name>StatementTemplateSendServlet</display-name>  
        <servlet-name>StatementTemplateSendServlet</servlet-name>  
        <servlet-class>com.thtf.commons.quartz.StatementTemplateSendServlet</servlet-class>  
        <load-on-startup>4</load-on-startup>  
    </servlet>  
      
    <welcome-file-list>  
        <welcome-file>index.jsp</welcome-file>  
    </welcome-file-list>  
</web-app>
  • 头声明可以使用的XML版本并给出文件的字符编码。
  • xmlns:命名空间。每一个.xml都应该有一个命名空间(是自己定义的,一般为全球唯一的网站作为.xml文件的命名空间),sun公司的规范,可能是要保证全球唯一性吧,所以用网址url。
  • xmlns:xsi声明XML Schema实例名称空间,验证有效性。
  • xsi:schemaLocation指定了web.xml真正遵循的约束,即xsd文件所在的位置。

web.xml标签

context-param元素
上下文参数:context-param 元素用来设定web应用的环境参数(context),它包含两个子元素:param-name和param-value。
filter元素
filter元素用于注册Web容器中的过滤器。
listener元素
listener元素用来注册一个监听器类,可以在Web应用中包含该类。

web.xml节点加载顺序

容器对于web.xml的加载过程:
context-param -> listener -> filter -> servlet

加载spring
比如filter 需要用到 bean ,但加载顺序是: 先加载filter 后加载spring,则filter中初始化操作中的bean为null;所以,如果过滤器中要使用到 bean,可以将spring 的加载 改成 Listener的方式:

<listener>    
        <listener-class>    
             org.springframework.web.context.ContextLoaderListener     
        </listener-class>    
</listener>

web.xml 的加载顺序是:[context-param -> listener -> filter -> servlet -> spring]

过滤器(filter)

  • Filter开发步骤
  1. 实现Filter接口并实现doFilter()方法
  2. 在web.xml文件中使用filter和filter-mapping元素对filter类注册,设置他说能拦截的资源
  • Filter链
    一个web应用中可以开发多个Filter,这些Filter组合起来称为Filter链。web服务器根据Filter的注册顺序决定调用先调用哪个Filter。

  • Spring中的一些Filter

  1. 字符编码过滤器CharacterEncodingFilter,从全局控制字符编码
  • Filter的生命周期
  1. Filter的创建,Filter的创建和销毁由web服务器负责。
  2. Filter的销毁,web容器调用destroy方法销毁Filter。
  3. FilterConfig接口,可以使用元素为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。

监听器(Listener)

servlet的监听器实现了javax.servlet.ServletContextListener 接口,也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。
ServletContextListener接口的源代码:

public abstract interface ServletContextListener extends EventListener{  
    public abstract void contextInitialized(ServletContextEvent paramServletContextEvent);  
    public abstract void contextDestroyed(ServletContextEvent paramServletContextEvent);  
}

Spring的ContextLoaderListener配置,用于加载Spring

<listener>
    <listener-class>org.springframework.web.context.ContextCleanupListener</listener-class>
  </listener>

参考链接

Java线程池

线程池

一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。
线程池模式一般分为两种:

  • 生产者消费者模式
  • L/F领导者与跟随者模式

new Thread的弊端

  • 每次new Thread新建对象性能低
  • 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom
  • 缺乏更多功能,如定时执行、定期执行、线程中断

Java线程池(4种)

Java线程池使用的是阻塞队列

  • newCachedThreadPool创建一个可缓存线程池
  • newFixedThreadPool 创建一个定长线程池
  • newScheduledThreadPool 创建一个定时线程池
  • newSingleThreadExecutor 创建一个单线程化的线程池

阻塞队列、非阻塞队列

【入队】
非阻塞队列:当队列满的时候,放入数据,数据丢失
阻塞队列:当队列满了,进行等待,什么时候队列中有出队,那么等待数据再放入
【出队】
非阻塞队列:如现队列中没有元素,取数据,得到的是null
阻塞队列:等待,什么时候放进去,再去出来

参考:
https://zh.wikipedia.org/wiki/%E7%BA%BF%E7%A8%8B%E6%B1%A0
https://blog.csdn.net/u011974987/article/details/51027795

Java多线程-2 Java对象模型

Java对象在堆内存中的表现形式

Java对象保存在堆内存中,一个Java对象包含3个部分:对象头实例数据对齐填充
对象头中包含锁状态标志线程持有的锁状态等标志。

Java对象模型(oop-klass model)

对象在JVM中的表示。

Java内存模型

计算机中的内存模型

  1. 在CPU和内存之间使用缓存的原因
    由于CPU执行速度过快,而从内存中读写数据的过程与之差距过大,导致CPU每次操作内存都要耗费很多的等待时间。所以在CPU和内存之间增加了高速缓存
    程序执行过程,将CPU需要的数据从主存中复制一份到高速缓存中,CPU运算时直接从它的高速缓存读取/写入数据,当运算结束后,再将高速缓存中的数据刷新到主存当中。

  2. 使用缓存带来的问题
    使用缓存在多核CPU多线程场景下,可能存在缓存一致性问题。在多核CPU中,每个核的自己的缓存中,关于同意数据的缓存内容可能不一致。

  3. 并发编程的问题
    为了保证数据安全,必须保证一下三个特性:

  • 原子性:一个操作CPU不能中途暂停然后再调度
  • 可见性:多个线程修改同一变量时,一个线程修改了变量的值,其它线程能立即看到修改的值
  • 有序性:程序执行的顺序按照代码的先后顺序

Java内存模型(JMM)

  1. Java内存模型规定了所有变量都存储在主内存中,每条线程还有自己的工作内存。
  2. 线程的工作内存中保存了该线程需要用到的主内存中变量的拷贝,线程对变量的所有操作必须在工作内存中完成,不能直接操作主内存。
  3. 不同线程间无法问问对方工作内存中的变量,线程间变量传递需要自己的工作内存和主存之间通过数据同步进行。
    JMM是和多线程相关的一组规则或规范,围绕多线程通信以及相关的一系列特性而建立的模型。目的是保证并发编程场景中的原子性、可见性和有序性。

Java内存模型的实现

volatile、synchronized、final、concurren包等。
synchronized保证方法和代码块的操作是原子性的。
volatile关键字 保证被其修饰的变量在被修改后可以立即同步到主内存,被其修饰的变量在每次使用之前都从主内存刷新。(可见性
在Java中,可以使用synchronized和volatile来保证多线程之间操作的有序性

参考:
http://zhuanlan.51cto.com/art/201807/577709.htm

volatile关键字

volatile关键字的两层语义

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  • 禁止进行指令重排序。
    假如线程1先执行,线程2后执行:
//线程1
boolean stop = false;
while(!stop){
    doSomething();
}
 
//线程2
stop = true;

下面解释一下这段代码为何有可能导致无法中断线程
每个线程在运行过程中都有自己的工作内存,那么线程1在运行的时候,会将stop变量的值拷贝一份放在自己的工作内存当中。那么当线程2更改了stop变量的值之后,但是还没来得及写入主存当中,线程2转去做其他事情了,那么线程1由于不知道线程2对stop变量的更改,因此还会一直循环下去。
volatile修饰之后

  1. 使用volatile关键字会强制将修改的值立即写入主存;
  2. 使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量stop的缓存行无效
  3. 由于线程1的工作内存中缓存变量stop的缓存行无效,所以线程1再次读取变量stop的值时会去主存读取。

volatile关键字作用

  • 保证操作的可见性
  • 保证有序性

volatile关键字使用场景

  1. 对变量的写操作不依赖于当前值
  2. 该变量没有包含在具有其他变量的不变式中

参考:
https://www.cnblogs.com/dolphin0520/p/3920373.html

Java内存模型、JVM内存模型、Java对象模型

Java内存模型(Java Memory Model)

JMM并不像JVM内存结构一样真实存在,它是一个抽象概念。
JMM是JVM规范中定义的和多线程相关的一组规则,围绕多线程通信以及相关的一系列特性而建立的模型。在Java语言上的表现就是volatile、synchronized等关键字。
JMM

JVM内存模型

JVM
JVM内存结构,由JVM规范定义。描述Java程序执行过程中,由JVM管理的不同数据区域。

Java对象模型

Java对象在JVM中存储有一定结构,Java对象自身的存储模型称之为Java对象模型。

总结

JVM内存结构,和Java虚拟机的运行时区域有关。
Java内存模型,和Java的并发编程有关。
Java对象模型,和Java对象在虚拟机中的表现形式有关。

参考:
http://www.hollischuang.com/archives/2509

Object类的equals(Object obj)和hashCode()

equals()方法实现源码

public boolean equals(Object obj) {
        return (this == obj);
    }

JDK的Object类中euqals()方法用于判断两个对象的地址是否相等,等价于“==”。

euqals()方法分为两类:

  1. 若某个类没有覆盖equals(),当通过equals比较时,实际比较的是两个对象的内存地址是否相等。即“==”。
  2. 覆盖了equals()方法,用equals()比较两个对象的内容是否相等。

hashCode()

每个Java类都包含hashCode() 函数。但是,仅仅当创建某个“类"的散列表时,该类的hashCode() 才有用。更通俗地说就是创建包含该类的HashMap,Hashtable,HashSet集合时,hashCode() 才有用。因为HashMap,Hashtable,HashSet就是散列表集合。
hashCode()的作用:确定该类的每一个对象在散列表中的位置。

hashCode()方法分为两类:

  1. 没有覆盖Object类的hashCode()方法,通过它比较的是两个对象的内存地址是否相等。即“==”
  2. 覆盖了hashCode()方法,让hashCode()通过其它方式比较两个对象的内容是否相等。

Java虚拟机如何执行线程同步

线程和共享数据

JVM中每个线程都独占一块栈内存,其中包括局部变量、线程调用的每个方法的参数和返回值。其他线程无法读取到该栈内存块中的数据。在JVM中,堆内存是所有线程共享的。堆中只包含对象,没有其他东西。除了栈和堆,还有一部分数据可能保存在JVM中的方法区中,比如类的静态变量。方法区和栈类似,其中只包含基本类型和对象应用。和栈不同的是,方法区中的静态变量可以被所有线程访问到。

对象和类的锁

JVM中有两块内存区域可以被所有线程共享:

  1. 堆,上面存放着所有对象
  2. 方法区,上面存放着静态变量
    为了协调多个线程之间的共享数据访问,虚拟机给每个对象和类都分配了一个锁。这个锁就像一个特权,在同一时刻,只有一个线程可以“拥有”这个类或者对象。如果一个线程想要获得某个类或者对象的锁,需要询问虚拟机。当一个线程向虚拟机申请某个类或者对象的锁之后,也许很快或者也许很慢虚拟机可以把锁分配给这个线程,同时这个线程也许永远也无法获得锁。当线程不再需要锁的时候,他再把锁还给虚拟机。这时虚拟机就可以再把锁分配给其他申请锁的线程。

锁的实现

锁是通过监视器实现的,监视器主要功能是监控一段代码,确保在同一时间只有一个线程在执行。

多次加锁

同一个线程可以对同一个对象进行多次加锁。每个对象维护着一个记录着被锁次数的计数器。

同步

在Java中,当有多个线程都必须要对同一个共享数据进行访问时,有一种协调方式叫做同步。Java语言提供了两种内置方式来使线程同步的访问数据:同步代码块和同步方法。

参考:
http://www.hollischuang.com/archives/1876

Spring AOP

AOP核心概念

  1. 连接点(Joinpoint):在程序执行过程中某个特定的点,如类初始化前、类初始化后
  2. 切点(Pointcut):切取的类中的方法,如横切的这个类中有两个方法,这两个方法都是连接点,对这两个方法的定位就称为切点
  3. 增强(Advice):织入到连接点上的一点程序
  4. 目标对象(Target):增强织入到的目标类
  5. 引介(Introduction):一种特殊的增强
  6. 织入(Weaving):将增强逻辑添加到目标对象的过程
  7. 代理(Proxy):一个类被AOP织入增强后,就会产生一个结果类,它融合了结果类和增强逻辑的代理类
  8. 切面(Aspect):由切点和增强组成,横切逻辑定义和连接点定义的组成

Spring对AOP的支持

Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。
Spring创建代理的规则:

  1. 默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
  2. 当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

AOP编程,程序员只需要参与三个部分:

  1. 定义普通业务组件
  2. 定义切入点,一个切入点可能横切多个业务组件
  3. 定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
    关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理(代理对象的方法=增强处理+被代理对象的方法。)

SpringAOP的简单实现

除了Spring提供的jar包,还需要额外下载两个jar包:aopalliance.jar和aspectjweaver.jar
XML实现方式:

//先定义一个接口
public interface HelloWorld
{
    void printHelloWorld();
    void doPrint();
}
//定义两个接口实现类
public class HelloWorldImpl1 implements HelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl1.printHelloWorld()");
    }
    
    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl1.doPrint()");
        return ;
    }
}
public class HelloWorldImpl2 implements HelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl2.printHelloWorld()");
    }
    
    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl2.doPrint()");
        return ;
    }
}
//横切关注点
public class TimeHandler
{
    public void printTime()
    {
        System.out.println("CurrentTime = " + System.currentTimeMillis());
    }
}

aop.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler">
                <aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addAllMethod" />
                <aop:after method="printTime" pointcut-ref="addAllMethod" />
            </aop:aspect>
        </aop:config>
</beans>
public static void main(String[] args)
{
    ApplicationContext ctx = 
            new ClassPathXmlApplicationContext("aop.xml");
        
    HelloWorld hw1 = (HelloWorld)ctx.getBean("helloWorldImpl1");
    HelloWorld hw2 = (HelloWorld)ctx.getBean("helloWorldImpl2");
    hw1.printHelloWorld();
    System.out.println();
    hw1.doPrint();
    
    System.out.println();
    hw2.printHelloWorld();
    System.out.println();
    hw2.doPrint();
}

代理模式

  • 静态代理
  • 动态代理
    • JDK动态代理
    • CGlib动态代理

JDK动态代理的核心接口和方法

public interface InvocationHandler {
    //proxy:被代理的类的实例
    //method:调用被代理的类的方法
    //args:该方法需要的参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
//loader:被代理的类的类加载器
//interfaces:被代理类的接口数组
//invocationHandler:就是刚刚介绍的调用处理器类的对象实例
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException

CGlib动态代理实现

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CGlibAgent implements MethodInterceptor {

    private Object proxy;

    public Object getInstance(Object proxy) {
        this.proxy = proxy;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.proxy.getClass());
        // 回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }
    //回调方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(">>>>before invoking");
        //真正调用
        Object ret = methodProxy.invokeSuper(o, objects);
        System.out.println(">>>>after invoking");
        return ret;
    }

    public static void main(String[] args) {
        CGlibAgent cGlibAgent = new CGlibAgent();
        Apple apple = (Apple) cGlibAgent.getInstance(new Apple());
        apple.show();
    }
}

参考:
http://www.cnblogs.com/xrq730/p/4919025.html
http://www.cnblogs.com/puyangsky/p/6218925.html

自动拆装箱

Java基本数据类型

字符类型char
布尔类型boolean
数值类型byte、short、int、long、float、double
实际上,Java中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作。

包装类型

基本数据类型 包装类型
char Char
boolean Boolean
byte Byte
short Short
int Integer
long Long
float Float
double Double

拆箱与装箱

基本数据类型转换成包装类的过程就叫装箱boxing
包装类转换成基本数据类型的过程就叫做拆箱unboxing

自动拆箱/装箱

自动将基本数据类型转换成包装类,或反之。

Integer i = 10; //替代Integer i = new Integer(10);
int j = i;

自动拆箱/装箱使用场景

  • 将基本数据类型放入集合类
List<Integer> lst = new ArrayList<>();
        for (int i = 1; i < 50; i ++){
            lst.add(i);
  • 装类型和基本类型的大小比较
  • 包装类型的运算
  • 三目运算符的使用
  • 函数参数与返回值
  • 自动拆装箱与缓存
  • 函数参数与返回值

参考:
http://www.hollischuang.com/archives/2700

Java集合

Java集合

主要有两个接口派生:CollectionMap
Collection

Map

Iterator接口

Iterator
它是Collection接口的父接口。
Collection接口有一个方法iterator() 返回一个Iterator迭代器对象。

Collection接口

Collection接口是Set、List、Queue接口的父接口。
Collection接口中定义了多种方法可以查看JDK文档。
主要用法有,添加元素、删除元素、返回Collection集合以及清空集合。

Set接口

Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。

List接口

List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。

Queue集合

Queue用户模拟队列这种数据结构,队列通常是指“先进先出”(FIFO,first-in-first-out)的容器。

Map接口

Map集合保存具有映射关系的数据。

Collection、Set、List、Map区别

differences

参考:
https://www.jianshu.com/p/589d58033841
https://blog.csdn.net/zhengqiqiqinqin/article/details/8434132

ClassLoader机制

类装载

Java所有类必须被装载到JVM中才能运行,装载工作由JVM的类装载器完成。类装载器所作的实质工作是把类文件从硬盘读取到内存中。JVM在装载类时,都是通过ClassLoader的loadClass()方法来装载class的,loadClass使用双亲委派模式。

ClassLoader和loadClass()源码

public abstract class ClassLoader

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

总结

类装载方式:

  1. 隐式加载,程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。
  2. 显式加载, 通过class.forname()等方法,显式加载需要的类。

类装载器实际有3个
ClassLoader

参考:
http://www.hollischuang.com/archives/199

Linux中mysql相关操作

与mysql相关linux操作命令

  • 查看是否已安装mysql rpm -qa mysql
  • 检测mysql是否启动 service mysqld status
  • 启动mysql service mysqld start或用脚本/etc/init.d/mysql start
  • 登陆
    无密码 mysql -u root -h 127.0.0.1
    有密码mysql -u root -h 127.0.0.1 -p

mysql中命令

首先进入mysql

  • 修改用户密码
    mysql>update mysql.user set password=password("新密码") where User="root";
    mysql>flush privileges;
    mysql>quit;
  • 显示数据库
    mysql>show databases;
    +--------------------+
    | Database |
    +--------------------+
    | information_schema |
    | mysql |
    | performance_schema |
    | test |
    +--------------------+
    4 rows in set (0.00 sec)
  • 使用数据库
    mysql>use test
    Database changed

数据库事务特性

数据库事务特性

原子性:事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性:事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性:多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性:已被提交的事务对数据库的修改应该永久保存在数据库中。

servlet接口

servlet

servlet是一个Java接口,定义的是一套处理网络请求的规范,不能处理请求,servlet不直接和客户端交互。servlet容器(如tomcat)负责和客户端交互,监听端口,将请求发送到对应的servlet处理,调用servlet的service方法,service方法返回response对象,tomcat在将response返回给客户端。

Java多线程-1

synchronized关键字

同步锁
Java中提供了多种同步锁的使用方式

  1. 对动态方法的修饰
    作用的是调用该方法的对象(对象的引用)
    public synchronized void doSomething(){}
  2. 对代码块的修饰
    作用的是调用该方法的对象(对象的引用)
public  void  increaseAmt(float increaseAmt){
		
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		synchronized (this) {
			System.out.println(this);
			amt+=increaseAmt;
		}
	}
  1. 对静态方法的修饰
    作用的是静态方法所在类的所有对象(对象的引用)
public synchronized static  void  increaseAmt(float increaseAmt){
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		amt+=increaseAmt;
	}
  1. 对类修饰
    作用的是静态方法所在类的所有对象
	synchronized (AccountSynchronizedClass.class) {
			amt-=decreaseAmt;
		}

synchronized实现原理

synchronized有两种使用形式,同步方法同步代码块

同步方法

同步方法的常量池中会有一个ACC_SYNCHRONIZED标志。当某个线程要访问某个方法的时候,会检查是否有ACC_SYNCHRONIZED,如果有设置,则需要先获得监视器锁,然后开始执行方法,方法执行之后再释放监视器锁。这时如果其他线程来请求执行方法,会因为无法获得监视器锁而被阻断住。值得注意的是,如果在方法执行过程中,发生了异常,并且方法内部并没有处理该异常,那么在异常被抛到方法外面之前监视器锁会被自动释放。

同步代码块

同步代码块使用monitorentermonitorexit两个指令实现。可以把执行monitorenter指令理解为加锁,执行monitorexit理解为释放锁。 每个对象维护着一个记录着被锁次数的计数器。未被锁定的对象的该计数器为0,当一个线程获得锁(执行monitorenter)后,该计数器自增变为 1 ,当同一个线程再次获得该对象的锁的时候,计数器再次自增。当同一个线程释放锁(执行monitorexit指令)的时候,计数器再自减。当计数器为0的时候。锁将被释放,其他线程便可以获得锁。

参考:
http://www.hollischuang.com/archives/1876
http://www.hollischuang.com/archives/1883

Maven settings.xml文件

settings.xml文件路径

Maven有两个settings.xml文件
路径分别是:%M2_HOME%/conf/settings.xml~/.m2/settings.xml

settings文件区别

  • %M2_HOME%/conf/settings.xml该配置为全局配置,影响所有用户
  • ~/.m2/settings.xml该配置为用户范围
    一般将全局配置的settings.xml文件复制到~/.m2/路径下作为用户范围的配置文件,
    通常都使用用户范围的settings.xml文件进行Maven的配置。

Mybatis动态sql

动态SQL

MyBatis采用基于OGNL的表达式来淘汰其他大部分元素。

  • if
  • choose(when, otherwise)
  • trim(where, set)
  • foreach

if

<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG
WHERE state = 'ACTIVE'
    <if test="title != null">
        AND title like #{title}
    </if>
</select>

choose, when, otherwise

类似Java中的switch语句

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

trim, where, set

where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG 
  <where> 
    <if test="state != null">
         state = #{state}
    </if> 
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ... 
</trim>

prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。

用于动态更新语句的解决方案叫做 set。set 元素可以用于动态包含需要更新的列,而舍去其它的。

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

和set元素等价的trim元素定义

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

foreach

动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

参考:
http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html

Spring常用注解

@Autowired注解

可以对类成员变量、setter方法及构造函数进行标注,完成自动装配的工作。

import org.springframework.beans.factory.annotation.Autowired;

public class Test {
    @Autowired
    private String user;

    @Autowired
    public void setUser(String user) {
        this.user = user;
    }

    @Autowired
    public Test(String user) {
        this.user = user;
    }
}

@qualifier 注解

当容器中存在同样类型的多个bean时,可以使用 @qualifier 注解指定注入 Bean 的名称。
@qualifier 标注的是成员变量、方法入参、构造函数入参。

@Autowired
public void setSender(@Qualifier("cellphoneSender")Sender sender) {
    this.sender = sender;
}

@component注解

参考:
https://blog.csdn.net/u010648555/article/details/76299467
https://blog.csdn.net/soonfly/article/details/70023707

Spring MVC流程

Spring MVC流程图

2018-10-14 6 47 17

各模块说明

  • DispatcherServlet
    DispatcherServlet
    使用Spring MVC,配置DispatcherServlet是第一步。
    DispatcherServlet是一个HttpServlet,所以可以配置多个DispatcherServlet。DispathcerServlet配置在web.xml中,
    用于拦截匹配的请求。将拦截到的请求分发到目标Controller进行处理。
<web-app>  
    <servlet>  
        <servlet-name>example</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>example</servlet-name>  
        <url-pattern>*.form</url-pattern>  
    </servlet-mapping>  
</web-app>  

servlet-name为这个servlet的名字,用于区分
load-on-startup标签为启动顺序,让这个servlet随servlet容器一起启动。
url-pattern为拦截规则,拦截.form结尾的请求
在DispatcherServlet的初始化过程中,框架会在web应用的 WEB-INF文件夹下寻找名为[servlet-name]-servlet.xml 的配置文件,生成文件中定义的bean。

<servlet>  
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
    <init-param>  
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/springMVC.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

指明了配置文件的文件名,不使用默认配置文件名。

Java多线程-3

进程和线程

操作系统中两者的区别:

  • 进程,是资源分配的最小单位
  • 线程,是CPU调度的最小单位

多进程与多线程
多进程指操作系统能同时运行多个任务(程序)
多线程指同一程序中有多个顺序流在执行

Java实现多线程的方式(3种)

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口

继承Thread类

class Thread1 extends Thread {
    private String name;
    public Thread1(String name) {
        this.name = name;
    }
   @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "run:" + i);
            try {
                sleep((int) Math.random() * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Thread1 mth1 = new Thread1("a");
        Thread1 mth2 = new Thread1("b");
        //start()方法调用,使线程变为可运行状态(Runnable),何时运行由操作系统决定
        mth1.start();
        mth2.start();
    }
}

程序运行main方法时,JVM启动一个进程,主线程main在main()被调用时创建。接着调用两个start()方法,另外两个线程也启动了,这样整个应用就在多线程下运行。

实现Runnable接口

覆盖run方法

class Thread2 implements Runnable {
    private String name;
    public Thread2(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + " run: " + i);
            try {
                Thread.sleep((int) Math.random() * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        new Thread(new Thread2("C")).start();
        new Thread(new Thread2("D")).start();
    }
}

所有的多线程代码都是通过运行Thread的start()方法来运行的
在Java中,每次程序至少启动2个线程,一个是main线程,一个是垃圾收集线程。每当使用java命令执行一个类时,实际上都会启动一个JVM,每个JVM实际就是在操作系统中启动了一个进程。

线程状态

Thread

  1. 新建状态(New),新创建了一个线程对象
  2. 就绪状态(Runnable),线程对象创建后,其他线程调用了该对线的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
  3. 运行状态(Running),就绪状态的线程获取了CPU,执行程序代码。
  4. 阻塞状态(Blocked),阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
    阻塞状态分3种:
    • 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。wait会释放持有的锁
    • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    • 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)
  5. 死亡状态(Dead),线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程调度

  1. 调度线程优先级,Java线程优先级用整数表示(1-10),Thread类有3个静态常量
static int MAX_PRIORITY //线程可以具有的最高优先级,取值为10
static int MIN_PRIORITY //线程可以具有的最低优先级,取值为1
static int NORM_PRIORITY //分配给线程的默认优先级,取值为5

Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级
线程的优先级有继承关系,比如A线程中创建了B线程,那么B和A具有相同的优先级

  1. 线程睡眠:Thread.sleep(long millis)方法,是线程转到阻塞状态。当睡眠结束,就转为就绪状态(Runnable)
  2. 线程等待:Object类中的wait()方法,导致当前线程等待,直到其他线程调用此对象的notify()方法或者notifyAll()唤醒方法。都是Object类中的方法,行为等价于调用wait(0)。
  3. 线程让步:Thread.yield()方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。
  4. 线程加入:join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一线程运行结束,当前线程再由阻塞转为就绪状态。
  5. 线程唤醒:Object类中notify()方法,唤醒在此对象监视器上等待的单个线程。

参考:
https://blog.csdn.net/Evankaka/article/details/44153709

Java反射机制

反射机制

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。
个人理解:在其他语言中,如Lisp可以将函数直接作为参数传递给函数(Lisp可以像处理数据一样处理自身代码),C中可以通过函数指针。Java无法直接将方法作为参数传递给方法,所以需要通过反射拿到关于类的信息并构造对象,通过这个包含类信息的对象,将可以实现把类中的方法作为参数传递给其他方法等功能。

主要作用

1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法
4.在运行时调用任意一个对象的方法
5.生成动态代理

相关API

【1】通过对象获取完整包名和类名

//实例化Class类,3种
Class demo0 = Class.forName("java.lang.String");
Class demo1 = new String().getClass();
Class demo2 = String.class;
//获取完整类名
System.out.println(demo0.getName());

运行结果:java.lang.String
【2】通过反射调用类中的方法

Class strClass = Class.forName("java.lang.String");
Method method = strClass.getMethod("toUpperCase");
System.out.println(method.invoke("asd"));

运行结果:ASD

invoke方法源码

@CallerSensitive
public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }

Linux挂载

文件系统

数据在计算机中都是以0和1的序列进行存储的,根据需要可以将数据分开保存到文件这样一个小单位中。而文件系统(file system)就是文件在逻辑上的组织形式,它以一种清晰的方式来存放各个文件,防止文件杂乱无章。
文件系统使用文件和树形目录的抽象逻辑概念代替了硬盘和光盘等物理设备使用数据块的概念,用户使用文件系统来保存数据不必关心数据实际保存在硬盘(或者光盘)的地址为多少的数据块上,只需要记住这个文件的所属目录和文件名。
常见文件系统:

  • 磁盘文件系统,FAT、NTFS、ext3、ext4
  • 网络文件系统,NFS(一种将远程主机上的目录经网络挂载到本地系统的一种机制)

文件系统中的相关目录

dev //硬件设备文件
media //挂载媒体设备,光驱、U盘
mnt //让用户临时挂载别的文件系统

磁盘分区

  • 主分区:最多只能有4个(由磁盘决定)
  • 扩展分区:最多只能有1个,主分区加扩展分区最多有4个,不能写入数据,只能包含逻辑分区
  • 逻辑分区:含于扩展分区
    img

格式化

目的是为了写入文件系统

设备挂载

每个设备都叫一个文件,制定文件系统中的某个目录到某个设备就叫挂载。这个目录就叫挂载点。

参考:
https://zh.wikipedia.org/wiki/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F
https://www.cnblogs.com/vamei/archive/2012/09/09/2676792.html

Maven仓库配置

仓库作用

统一存储所有Maven项目需要的构件(一般为jar包)

仓库分类

  • 远程仓库
  • 本地仓库(默认在~/.m2/repository/目录下)
    Maven从远程仓库下载需要的构件到本地仓库再使用

本地仓库配置(修改~/.m2/settings.xml文件)

  • 修改仓库目录
    D:/Maven/maven_local_repository

远程仓库配置(修改pom.xml文件)

示例:

<repositories>
    <repository>
      <id>jboss</id>
      <name>JBoss Repository</name>
      <url>http://repository.jboss.com/maven2/</url>
      <releases>
        <enabled>true</enabled>
        <updatePolicy>daily</updatePolicy>
      </releases>
      <snapshots>
        <enabled>false</enabled>
        <checksumPolicy>warn</checksumPolicy>
      </snapshots>
      <layout>default</layout>
    </repository>
 </repositories>

repositories下可声明多个repository

Maven安装(windows)

Maven下载地址

http://maven.apache.org/download.cgi
apache-maven-3.5.4-bin.zip

Maven本地安装

  • 解压apache-maven-3.5.4-bin.zip(如:D:\Maven\apache-maven-3.5.2)

  • 添加环境变量

    • 系统变量中创建M2_HOME,变量值为D:\Maven\apache-maven-3.5.2
    • Path中添加变量值%M2_HOME%\bin

正向/反向代理

用途

正向代理:

  1. 突破访问限制
  2. 提高访问速度
  3. 隐藏客户端真实IP

反向代理:

  1. 隐藏服务器真实IP
  2. 负载均衡,根据真实服务器负载情况,将客户端请求分发到不同的真实服务器上。
  3. 提高访问速度
  4. 提供安全保障

Lambda Calculus

lambda calculus

lambda演算是一套从数学逻辑中发展,以变量绑定和替换的规则,来研究函数如何抽象化定义、函数如何被应用以及递归的形式系统。Lambda演算作为一种广泛用途的计算模型,可以清晰地定义什么是一个可计算函数,而任何可计算函数都能以这种形式表达和求值。(由Alonzo Church引入以定义“可计算函数”)

lambda表达式定义

lambda表达式用以下格式定义
λ变量.表达式体

规约

lambda函数如何工作——归约。
规约有三种规则

  • α-转换(α-conversion)
    alpha转换的意思是变量名不影响函数含义的意思。
    λa b.a+bλx y.x+y函数的功能并没有发生变化
  • β归约(β-reduction)
    beta归约的规则是把函数“应用”到传入的参数上。
    lambda函数λa b.a+b应用在传入的两个参数1和2,那么a和b分别就替换成1和2,表达式体中的a和b的位置也分别被替换成1和2λ1 2.1+2
  • η变换(η-conversion)
    如果两个函数对于所有相同的传入的参数都能得到一样的结果,则两个函数相等。

匿名函数

lambda变量里不能调用一个外部的绑定名字的函数,当然Lambda函数本身也不能有名字(所以在某些编程语言里Lambda函数这个概念又叫做“匿名函数”)。

参考:
https://zh.wikipedia.org/wiki/%CE%9B%E6%BC%94%E7%AE%97
http://www.cppblog.com/wuwu/archive/2014/07/07/207556.aspx

枚举类

不使用枚举定义常量

public class Demo {
    public static final int MONDAY =1;
    public static final int TUESDAY=2;
    public static final int WEDNESDAY=3;
    public static final int THURSDAY=4;
    public static final int FRIDAY=5;
    public static final int SATURDAY=6;
    public static final int SUNDAY=7;
}

使用枚举类型定义常量

enum Demo {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

枚举类型实现原理

编译器帮助生成了一个Day类(final,无法被继承),该类继承自java.lang.Enum类。编译器还帮助生成了7个Day类型的实例对象分别对应枚举中定义的7个日期。

static 
    {    
        //实例化枚举实例
        MONDAY = new Day("MONDAY", 0);
        TUESDAY = new Day("TUESDAY", 1);
        WEDNESDAY = new Day("WEDNESDAY", 2);
        THURSDAY = new Day("THURSDAY", 3);
        FRIDAY = new Day("FRIDAY", 4);
        SATURDAY = new Day("SATURDAY", 5);
        SUNDAY = new Day("SUNDAY", 6);
        $VALUES = (new Day[] {
            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }

枚举类型用法

  1. 常量
public enum Color {  
  RED, GREEN, BLANK, YELLOW  
}  
  1. switch
enum Signal {  
    GREEN, YELLOW, RED  
}  
public class TrafficLight {  
    Signal color = Signal.RED;  
    public void change() {  
        switch (color) {  
        case RED:  
            color = Signal.GREEN;  
            break;  
        case YELLOW:  
            color = Signal.RED;  
            break;  
        case GREEN:  
            color = Signal.YELLOW;  
            break;  
        }  
    }  
}
  1. 向枚举中添加新方法
public enum Color {  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
    // 普通方法  
    public static String getName(int index) {  
        for (Color c : Color.values()) {  
            if (c.getIndex() == index) {  
                return c.name;  
            }  
        }  
        return null;  
    }  
    // get set 方法  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getIndex() {  
        return index;  
    }  
    public void setIndex(int index) {  
        this.index = index;  
    }  
}
  1. 覆盖枚举的方法
public enum Color {  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
    //覆盖方法  
    @Override  
    public String toString() {  
        return this.index+"_"+this.name;  
    }  
}  
  1. 实现接口
public interface Behaviour {  
    void print();  
    String getInfo();  
}  
public enum Color implements Behaviour{  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
//接口方法  
    @Override  
    public String getInfo() {  
        return this.name;  
    }  
    //接口方法  
    @Override  
    public void print() {  
        System.out.println(this.index+":"+this.name);  
    }  
}  
  1. 使用接口组织枚举
public interface Food {  
    enum Coffee implements Food{  
        BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
    }  
    enum Dessert implements Food{  
        FRUIT, CAKE, GELATO  
    }  
}

参考:
https://blog.csdn.net/javazejian/article/details/71333103
http://www.hollischuang.com/archives/195

List集合

ArrayList

ArrayList实现了List接口,是顺序容器,允许放入null元素,底层通过数组实现。该类除未实现同步外,其余大部分和Vector大致相同。

  • ArrayList属性
    capacity,表示底层数组的实际大小,想容器添加元素,若容量不足,容器会自动增大底层数组大小。
  • ArrayList常用方法
  1. remove(),remove(int index)删除指定位置的元素,remove(Object o)删除第一个满足o.equals(elementData[index])的元素。
  2. add(),添加元素前会检查剩余空间,容量不足会自动扩容。
  3. set(),直接对数组的指定位置赋值即可。
public E set(int index, E element) {
    rangeCheck(index);//下标越界检查
    E oldValue = elementData(index);
    elementData[index] = element;//赋值到指定位置,复制的仅仅是引用
    return oldValue;
}
public E remove(int index) {
    rangeCheck(index);
    modCount++;
    E oldValue = elementData(index);
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index, numMoved);
    elementData[--size] = null; //clear to let GC do its work
    return oldValue;
}

LinkedList

LinkedList同时实现了List和Deque接口,它既可以看作一个顺序容器,也可看作一个队列(Queue),还可看作一个栈(Stack)。底层通过双向链表实现,双向链表的每个节点用内部类Node()表示。LinkedList没有实现同步(synchronized),多线程并发访问,可以先用Collections.synchronizedList()方法对其进行包装。

private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;
    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}
  • LinkedList方法
  1. add(),add(E e)在末尾插入元素和add(int index, E element)指定位置插入元素。
  2. remove(),remove(Object o)删除和指定元素相等的第一个元素和remove(int index)删除指定下标处元素。

ArrayDeque

Java有Stack类和Queue接口,但当使用栈时,不推荐使用Stack,而是ArrayDeque,使用队列时也首选ArrayDeque。
ArrayDeque底层是有循环数组实现(circular array),数组的任何一点都可以看作起点或终点,ArrayDeque是非线程安全的,该容器不允许放入null元素。

  • ArrayDeque方法
  1. addFirst(E e),在Deque的首端插入元素。
  2. addLast(E e),在Deque的尾端插入元素。
  3. pollFirst(E e),删除并返回Deque首端元素。
  4. pollLast(E e),删除并返回Deque尾端元素。
  5. peekFirst(E e),返回Deque首端元素。
  6. peekLast(E e),返回Deque尾端元素。

HashMap扩容机制

计算初始化容量的算法

int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;

HashMap容量初始化的合理值

当我们明确知道HashMap中元素的个数的时候,把默认容量设置成expectedSize / 0.75F + 1.0F 是一个在性能上相对好的选择。

Javap指令

作用

  1. javap可以对.class文件进行反编译(一般不用来反编译)
  2. 查看Java编译器为我们生成的字节码

用法

用法: javap <options> <classes>

-help 帮助
-l 输出行和变量的表
-public 只输出public方法和域
-protected 只输出public和protected类和成员
-package 只输出包,public和protected类和成员,这是默认的
-p -private 输出所有类和成员
-s 输出内部类型签名
-c 输出分解后的代码,例如,类中每一个方法内,包含java字节码的指令,
-verbose 输出栈大小,方法参数的个数
-constants 输出静态final常量

参考:
http://www.hollischuang.com/archives/1107

算法导论

算法导论

分为两个部分

  • 算法分析(analysis)
  • 算法设计(design)

算法分析是理论研究,是关于计算机程序性能(computer program performance)和资源利用(resource usage)的研究。
首先需要关注性能;这里的资源代表如通信,存储器(内存或磁盘)

思考

A: In programming, what is more important than performance?
Q: Correctness(正确性)...
A: Why do wo bother and why study algorithms and performance?
Q: 1. 通常性能的好与坏直接决定可行还是不可行。算法总是处于解决问题的最前沿,算法能够将不可行变成可行。
2. 算法是一种描述程序行为的语言,它已形成了一种广泛应用于计算机科学领域的语言,被所有实践者所采用的理论语言,它是一种让程序最为简洁的思考方式。

算法的运行时间(running time)

影响因素:

  • 软硬件因素
  • 输入本身(input,如插入排序倒序)
  • 输入的规模(size,如元素个数)
  • 算法的好坏

将依输入的规模将其参数化,之后会把运行时间看作待排列数据规模的函数
运行时间的上界,代表了对用户的承诺

Kinds of analysis

  • 最坏情况分析(worst-case analysis)
    T(n)定义为输入规模为n时的最长运行时间
  • 平均情况(Average-case)
    T(n)就成了输入规模n之下所有可能输入的期望时间

关注运行时间的增长

渐进分析
不关注实际的运行时间,只关注它如何增长

渐进符号(asymptotic notation)
Θ-notation,drop low order terms and ignore leading constants
在公式中,弃去它的低阶项,并忽略前面的常数因子
例子: 公式3n^3+90n^2-5n+6046=Θ(n^3)

T(n)=O(f(n)),f(n)为算法执行次数与输入规模n的函数。

Tomcat设置JVM内存大小

JVM分配内存

AVA程序启动时JVM都会分配一个初始内存和最大内存给这个应用程序。这个初始内存和最大内存在一定程度都会影响程序的性能。这个初始内存和最大内存在一定程度都会影响程序的性能。比如说在应用程序用到最大内存的时候,JVM是要先去做垃圾回收的动作,释放被占用的一些内存。

调整Tomcat的启动时初始内存和最大内存

调整Tomcat的启动时初始内存和最大内存需要向JVM声明。
-Xms-Xmx来调整应用程序的初始内存和最大内存。一般把-Xms和-Xmx设为一样大,堆的最大值受限于系统使用的物理内存。建议堆的最大值设置为可用内存的最大值的80%。

设置方法

Windows下,在文件/bin/catalina.bat
JAVA_OPTS='-Xms【初始化内存大小】-Xmx【可以使用的最大内存】'
如JAVA_OPTS='-Xms256m-Xmx512m'

参考:
http://developer.51cto.com/art/201009/227043.htm

Spring体系结构、各模块jar包依赖

Spring 结构图

1. Spring 3结构图
Spring 3
2. Spring 4结构图
Spring 4

Spring各模块之间依赖关系

  • Spring 3 各模块依赖关系(19个jar)
  1. Core
    spring-core
  2. aop
    spring-aop
  3. data base
    data base
  4. web
    web
  5. test & spring-context-support
    test & spring-context-support
  • Spring 4 各模块依赖关系(20个jar)
    Spring 4移除了Spring 3的structs,添加了messaging和websocket,其他模块保持不变
    websocket & messaging
    websocket & messaging

Mybatis一级缓存二级缓存

缓存

缓存的解释:
从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,而是直接从缓存中读取,避免频繁操作数据库,减轻数据库的压力,同时提高系统性能。

MyBatis默认情况下是没有开启缓存的,除了局部的session缓存。要开启二级缓存,需要在SQL映射文件中添加一行
<cache/>
这个简单语句的效果如下

  • 映射语句文件中的所有 select 语句将会被缓存。
  • 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
  • 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
  • 根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
  • 缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
  • 缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,-而不干扰其他调用者或线程所做的潜在修改。
    这些属性可以通过缓存标签修改,如
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。
可用的收回策略有:

  • LRU – 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

参考:
http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

IDEA project structure配置

Project

project

Modules

modules

  1. 增删依赖项目,每个依赖项目相当于一个模块。
  2. 每个模块都对应了Sources、Paths、Dependencies 三个配置选项
    • Sources:显示项目的目录资源,那些是项目部署的时候需要的目录
    • Paths:可以指定项目的编译输出目录,即项目类和测试类的编译输出地址(替换掉了Project的默认输出地址)
    • Dependencies:项目的依赖
  3. 增删框架:每个子项目之下都可以定义它所使用的框架
    web部分的设置
    web

Libraries

显示所添加的jar包

Facets

在左边选择面板点击某个技术框架,右边将会显示这个框架的一些设置

Artifacts

项目的打包部署设置
exploded:在这里你可以理解为展开,不压缩的意思。也就是war、jar等产出物没压缩前的目录结构。建议在开发的时候使用这种模式,便于修改了文件的效果立刻显现出来。
Artifacts
输出目录理解:
点击运行tomcat时

  • 编译,编译后class文件存放在指定的项目编译输出目录下
  • 根据artifact中的设定对目录结构进行创建
  • 拷贝web资源的根目录下的所有文件到artifact的目录下
  • 拷贝编译输出目录下的classes目录到artifact下的WEB-INF下
  • 拷贝lib目录下所需的jar包到artifact下的WEB_INF下
  • 运行server,运行成功后,如有需要,会自动打开浏览器访问指定url

参考:
https://www.cnblogs.com/deng-cc/p/6416332.html

Java异常处理

异常架构

Throwable
Throwable类的几个重要方法:

  • String getMessage():获得发生异常的详细消息。
  • void printStackTrace():打印异常堆栈跟踪信息。
  • String toString():获得异常对象的描述。
  • Throwable getCause():返回抛出异常的原因。如果 cause 不存在或未知,则返回 null。

RuntimeException和非运行时异常

Exception分为 运行时异常(RuntimeException)和非运行时异常,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。
运行时异常都是RuntimeException类及其子类异常,如NullPointerException、 IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。
非运行时异常是RuntimeException以外的异常,从程序语法角度讲是必须进行处理的异常,如果不 处理,程序就不能编译通过。

异常处理的原则

  1. 能处理就早处理,抛出不去还不能处理的就想法消化掉或者转换为RuntimeException处理。
  2. 对于检查异常,如果不能行之有效的处理,还不如转换为RuntimeException抛出。这样也让上层的代码有选择的余地――可处理也可不处理。
  3. 对于一个应用系统来说,应该有自己的一套异常处理框架,这样当异常发生时,也能得到统一的处理风格,将优雅的异常信息反馈给用户。

异常转译

异常转译是将一种异常转换为另一种异常。
exception

参考:
http://www.cnblogs.com/WayneZeng/archive/2012/09/23/2699177.html

快速排序Java

quick-sort

快速排序使用分治法将一个序列(list)分成两个子序列
步骤:

  1. 从数列中挑出一个元素,称为“基准”(pivot)
  2. 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。

Java实现

public static void quickSort(int[] arr){
    qsort(arr, 0, arr.length-1);
}
private static void qsort(int[] arr, int low, int high){
    if (low < high){
        int pivot=partition(arr, low, high);        //将数组分为两部分
        qsort(arr, low, pivot-1);                   //递归排序左子数组
        qsort(arr, pivot+1, high);                  //递归排序右子数组
    }
}
private static int partition(int[] arr, int low, int high){
    int pivot = arr[low];     //枢轴记录
    while (low<high){
        while (low<high && arr[high]>=pivot) --high;
        arr[low]=arr[high];             //交换比枢轴小的记录到左端
        while (low<high && arr[low]<=pivot) ++low;
        arr[high] = arr[low];           //交换比枢轴小的记录到右端
    }
    //扫描完成,枢轴到位
    arr[low] = pivot;
    //返回的是枢轴的位置
    return low;
}

参考:
http://wiki.jikexueyuan.com/project/easy-learn-algorithm/fast-sort.html
https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F
http://blog.51cto.com/flyingcat2013/1281614

log4j

Log4J的配置文件

用来设置记录器级别,存放器,和布局

  1. 配置文件
    log4j配置文件基本格式
# 配置根Logger
log4j.rootLogger=[level],apenderName1,appenderName2,...

# 配置日志信息输出目的地Appender
log4j.appender.appenderName=fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1=value1
...
log4j.appender.appenderName.option1=valueN

# 配置日志信息的格式(布局)
log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1=value1
...
log4j.appender.appenderName.layout.optionN=valueN

[level]为日志输出级别,共有5级

FATAL   0   //
ERROR   3   //为严重错误 主要是程序的错误
WARN    4  //为一般警告,比如session丢失
INFO    6  //为一般要显示的信息,比如登录登出
DEBUG   7  //为程序的调试信息

Appender为日志输出目的地,Log4j提供的appender有以下几种:

org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

Layout:日志输出格式,Log4j提供的layout有以下几种:

org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

打印参数: Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,如下:

%m   输出代码中指定的消息
%p   输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r   输出自应用启动到输出该log信息耗费的毫秒数
%c   输出所属的类目,通常就是所在类的全名
%t   输出产生该日志事件的线程名
%n   输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
%d   输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss ,SSS},输出类似:2002年10月18日  22 : 10 : 28 , 921
%l   输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java: 10 )

示例

【配置文件】

### set log levels ###
log4j.rootLogger = debug ,  stdout ,  D ,  E

### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{ 1 }:%L - %m%n

### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 保存异常信息到单独文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/error.log ## 异常日志文件名
log4j.appender.D.Append = true
log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

【代码中使用】

public   class  TestLog4j  {
     public   static   void  main(String[] args)  {
        PropertyConfigurator.configure( " D:/Code/conf/log4j.properties " );
        Logger logger  =  Logger.getLogger(TestLog4j. class );
        logger.debug( " debug " );
        logger.error( " error " );
    } 
 }

参考:
https://blog.csdn.net/zhshulin/article/details/37937365

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.