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:是以固定的延时去执行任务,延时是指上一次执行成功之后和下一次开始执行的之前的时间。