最新整理

158 阅读11分钟

docker

  • docker ps -a 查看容器状态
  • docker run -it --name=容器名称 镜像名称:标签 交互式运行容器
  • docker run -di --name=容器名称 镜像名称:标签 守护式创建运行容器
  • docker exec -it 容器名称(或者容器ID) /bin/bash 进入守护式容器方式
  • docker stop 容器名称(或者容器ID) 停止容器
  • docker start 容器名称(或者容器ID) 启动容器
  • docker cp
  • docker rm mycentos3 删除容器
  • docker rmi mycentos3 删除镜像
  • docker inspect 容器名称 查看容器各种数据
  • docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称(容器ID) 查看容器ip地址
  • docker images 查看镜像文件
  • docker pull 容器名称 拉取镜像

tomcat 优化方案

  • 1.采用动静分离的方式,nginx负责静态资源的访问,tomcat负责jsp文件的解析
  • 2.禁用AJP服务
  • 3.启用线程池执行器,优化线程池数量的大小,并配置到连接器上
  • 4.jvm调优,使用G1垃圾收集器
  • 5.修改tomcat的运行模式,tomcat8以下版本使用nio模式,tomcat8以上版本使用nio2

zookeeper

简介:zookeeper主要用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项管理等
zookeeper = 文件系统 + 监听通知机制

ls / 查看根目录下所有node节点
create /zkPro myData 创建node节点zkPro 并将myData存储到该节点中
get /zkPro 获取node节点zkPro下存储的信息
set /zkPro myData123 通过set命令对zkPro节点关联的字符串设值
delete /zkPro 删除节点

volatile关键字(保证有序性,不保证原子性)

作用:一个线程对使用了volatile关键字修饰的数据进行修改后,会将最新值强制刷新到主内存中,并且使其他缓存了该数据的所有线程数据失效清空,必须从主内存中重新读取最新值,保证数据的可见性。
防止指令重排序的问题。典型代表:双重锁的单例模式

1.分配内存;
2.初始化对象;
3.将指针指向分配的地址。

public class Test{
	private static volatile Test test;
	public Test getInstance(){
		if(null == test) {
			synchronized(Test.class){
				if(test == null) {
					test = new Test();
				}	
			}
		}
		return test;
	}

}
  • 原子性:是指一个操作要么执行完成,要么不执行,不可以执行到一半时,中途暂停操作然后再调度执行
  • 可见性:每一个线程都有一个自己的本地内存,所有线程共享一个主线程,如果一个线程对主线程中的变量进行了修改,而另一个线程并不知道,这就是线程的不可见性
  • 有序性:程序执行的顺序按照代码的先后顺序执行,称为有序性

ThreadLocal类解析

private static final ThreadLocal<Map<String,String>> data = new ThreadLocal<Map<String,String>>(){
        @Override
        protected Map<String,String> initialValue() {
            return new HashMap<String, String>();
        }
    };

上述代码是new了一个重写了父类initialValue方法的对象;每一个线程都有一个ThreadLocalMap对象; ThreadLocal类中有一个静态内部类ThreadLocalMap,ThreadLocalMap类中有一个Entry类,是一个key,value键值对形式的对象,我们的数据是存储在ThreadLocalMap类定义的Entry对象中的; ThreadLocal类中使用一个初始长度为16的Entry数组来存储Entry对象,Entry对象的key即为当前线程hashCode值,value即为initialValue方法的初始对象.

调用ThreadLocal类的get()方法,底层则是通过获取当前线程,通过当前线程hashCode获取ThreadLocalMap对象, 再通过当前线程对象hashCode值来获取ThreadLocalMap对象中存储的Entry实体,并返回该实体的value值,即获取到initialValue()方法中的HashMap对象

linux

  • tail -f fileName 持续监控输出指定文件内容

  • tail -n fileName 查看从文件结尾至n行的内容

  • tail -100f fileName 查看文件结尾至100行处的内容,并持续输出

  • mkdir fileName 创建文件夹

  • rmdir fileName 删除文件夹

  • touch file 创建file文件

  • rm file 删除文件

  • vi file 打开文件并处于编辑状态 再按i 进入编辑模式

  • 按esc退出 按:wq 退出并保存 按:q!退出不保存

  • cp file1 file2 从file1上复制文件file2

  • mv file1 file2 将文件file1重命名为file2

tar 打包命令

  • -c 创建一个新的tar文件
  • -v 显示运行过程的信息
  • -f 指定文件名
  • -z 调用gzip压缩命令进行压缩
  • -t 查看压缩文件的内容

MVCC 多版本并发控制 用来避免写操作堵塞读操作的并发问题

本质:一个事务,不管其执行多长时间,其内部看到的数据是一致的

实现原理:

  • 1.select操作: InnoDB只查找版本早于(包含等于)当前事务版本的数据行。可以确保事务读取的行,要么是事务开始前就已存在,或者事务自身插入或修改的记录。 行的删除版本要么未定义,要么大于当前事务版本号。可以确保事务读取的行,在事务开始之前未删除。
  • 2.insert操作。将新插入的行保存当前版本号为行版本号。
  • 3.delete操作。将删除的行保存当前版本号为删除标识。
  • 4.update操作。变为insert和delete操作的组合,insert的行保存当前版本号为行版本号,delete则保存当前版本号到原来的行作为删除标识。
  • 由于旧数据并不真正的删除,所以必须对这些数据进行清理,innodb会开启一个后台线程执行清理工作,具体的规则是将删除版本号小于当前系统版本的行删除,这个过程叫做purge。

java线程池类ThreadPoolExecutor使用详解

该类的构造方法如下:
```java
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
corePoolSize		核心线程数
maximumPoolSize 	最大线程数  
keepAliveTime		最大线程数超过核心线程数后,多余线程空闲多久后会被销毁回收
unit 				时间单位
workQueue			工作队列(包括SynchronousQueue直接提交队列,ArrayBlockingQueue有界任务队列,LinkedBlockingQueue无界任务队列,PriorityBlockingQueue优先任务队列)
					SynchronousQueue直接提交队列:	
						使用该队列后,提交的任务不会被保存,总是会马上执行,如果任务数大于核心线程数,会尝试新建线程来执行,超过最大线程数会采用设置的执行策略handler
					ArrayBlockingQueue有界任务队列:
						使用该队列后,若有新任务加入,会先创建新的线程来执行,若达到核心线程数,会将多余的任务放入指定大小的该任务队列中,直至达到该任务队列的初始容量,会重新创建新的线程来执行多余的任务,直至达到最大线程数后,若还有多余的任务加入,执行拒绝策略。
					LinkedBlockingQueue无界任务队列:
						使用无界任务队列,线程池的任务队列可以无限制的添加新的任务,而线程池创建的最大线程数量就是你corePoolSize设置的数量,也就是说在这种情况下maximumPoolSize这个参数是无效的,哪怕你的任务队列中缓存了很多未执行的任务,当线程池的线程数达到corePoolSize后,就不会再增加了;若后续有新的任务加入,则直接进入队列等待,当使用这种任务队列模式时,一定要注意你任务提交与处理之间的协调与控制,不然会出现队列中的任务由于无法及时处理导致一直增长,直到最后资源耗尽的问题。
					PriorityBlockingQueue优先任务队列:
						PriorityBlockingQueue其实是一个特殊的无界队列,它其中无论添加了多少个任务,线程池创建的线程数也不会超过corePoolSize的数量,只不过其他队列一般是按照先进先出的规则处理任务,而PriorityBlockingQueue队列可以自定义规则根据任务的优先级顺序先后执行。	

常用的四种拒绝策略
AbortPolicy策略:该策略会直接抛出异常,阻止系统正常工作;
CallerRunsPolicy策略:如果线程池的线程数量达到上限,该策略会把任务队列中的任务放在调用者线程(即让主线程帮忙执行)当中运行,以缓解执行压力;
DiscardOledestPolicy策略:该策略会丢弃任务队列中最老的一个任务,也就是当前任务队列中最先被添加进去的,马上要被执行的那个任务,并尝试再次提交;
DiscardPolicy策略:该策略会默默丢弃无法处理的任务,不予任何处理。当然使用此策略,业务场景中需允许任务的丢失;

LinkedBlockingQueue和ArrayBlockingQueue的比较:
相同点:
	1.LinkedBlockingQueue和ArrayBlockingQueue都是可阻塞的队列
	2.内部都是使用ReentrantLock和Condition来保证生产和消费的同步;
	3.当队列为空,消费者线程被阻塞;当队列装满,生产者线程被阻塞;
	4.使用Condition的方法来同步和通信:await()和signal()
不同点:
	1.锁机制不同

	inkedBlockingQueue中的锁是分离的,生产者的锁PutLock,消费者的锁takeLock

	ArrayBlockingQueue生产者和消费者使用的是同一把锁;

	2、底层实现机制也不同

	nkedBlockingQueue内部维护的是一个链表结构。

	在生产和消费的时候,需要创建Node对象进行插入或移除,大批量数据的系统中,其对于GC的压力会比较大。

	ArrayBlockingQueue内部维护了一个数组

	在生产和消费的时候,是直接将枚举对象插入或移除的,不会产生或销毁任何额外的对象实例。

	3、构造时候的区别

	nkedBlockingQueue有默认的容量大小为:Integer.MAX_VALUE,当然也可以传入指定的容量大小

	ArrayBlockingQueue在初始化的时候,必须传入一个容量大小的值

	4、执行clear()方法  
	
        LinkedBlockingQueue执行clear方法时,会加上两把锁

	5、统计元素的个数
	LinkedBlockingQueue中使用了一个AtomicInteger对象来统计元素的个数,ArrayBlockingQueue则使用int类型来统计元素。

常见的四种线程池
	newFixedThreadPool:
		固定大小的线程池,可以指定线程池的大小,该线程池corePoolSize和maximumPoolSize相等,阻塞队列使用的是LinkedBlockingQueue,大小为整数最大值。该线程池中的线程数量始终不变,当有新任务提交时,线程池中有空闲线程则会立即执行,如果没有,则会暂存到阻塞队列。对于固定大小的线程池,不存在线程数量的变化。同时使用无界的LinkedBlockingQueue来存放执行的任务。当任务提交十分频繁的时候,LinkedBlockingQueue迅速增大,存在着耗尽系统资源的问题。而且在线程池空闲时,即线程池中没有可运行任务时,它也不会释放工作线程,还会占用一定的系统资源,需要shutdown。
	newSingleThreadExecutor:
		单个线程线程池,只有一个线程的线程池,阻塞队列使用的是LinkedBlockingQueue,若有多余的任务提交到线程池中,则会被暂存到阻塞队列,待空闲时再去执行。按照先入先出的顺序执行任务。
	newCachedThreadPool:
		缓存线程池,缓存的线程默认存活60秒。线程的核心池corePoolSize大小为0,核心池最大为Integer.MAX_VALUE,阻塞队列使用的是SynchronousQueue。是一个直接提交的阻塞队列,    他总会迫使线程池增加新的线程去执行新的任务。在没有任务执行时,当线程的空闲时间超过keepAliveTime(60秒),则工作线程将会终止被回收,当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销。如果同时又大量任务被提交,而且任务执行的时间不是特别快,那么线程池便会新增出等量的线程池处理任务,这很可能会很快耗尽系统的资源。
	newScheduledThreadPool:
		定时线程池,该线程池可用于周期性地去执行任务,通常用于周期性的同步数据。scheduleAtFixedRate:是以固定的频率去执行任务,周期是指每次执行任务成功执行之间的间隔。schedultWithFixedDelay:是以固定的延时去执行任务,延时是指上一次执行成功之后和下一次开始执行的之前的时间。