深圳企业网站建设公司哪家好,阿里云可以建网站吗,用html制作百度首页,金华高端网站建设公司线程与进程
线程就是一个指令流#xff0c;将一条条指令以一定的顺序交给CPU运行#xff0c;是操作系统进行运算调度的最小单位进程是正在运行程序的实例#xff0c;进程包含了线程不同进程使用不同的内存空间#xff0c;在当前进程下的所有线程可以共享内存空间。
并发与…线程与进程
线程就是一个指令流将一条条指令以一定的顺序交给CPU运行是操作系统进行运算调度的最小单位进程是正在运行程序的实例进程包含了线程不同进程使用不同的内存空间在当前进程下的所有线程可以共享内存空间。
并发与并行
并发(多线程操作同一个资源,交替执行) CPU一核, 模拟出来多条线程,天下武功,唯快不破,快速交替并行(多个人一起行走, 同时进行) CPU多核,多个线程同时进行 ; 使用线程池操作
同步和异步
同步发出一个调用以后一直等待直到得到结果返回异步调用在发出以后不用等待返回结果直接返回
线程创建的方式 继承Thread类 重写run方法调用start方法开启线程 实现runnable接口 重写run方法调用start方法开启线程 实现Callabel接口 重写call方法有返回值用Future/FutureTask的get方法获取调用start方法启动线程 线程池创建创建线程
runnable接口和callable接口的区别
runnable接口的run方法没有返回值callable接口的call方法有返回值可以通过Future/FutureTask的get方法获取runnable的run方法不能抛出异常只能捕获callable的call方法可以抛出异常
run和start方法的区别
run方法封装了线程要执行的方法可以被调用多次普通方法调用start方法用来启动线程通过该方法执行run方法只能被调用一次
线程的状态
public enum State {// 创建NEW,// 可运行RUNNABLE,// 阻塞BLOCKED,// 等待死死地等WAITING,// 超时等待TIMED_WAITING,// 终止TERMINATED;
} 新建 当一个线程对象被创建但还未调用 start 方法时处于新建状态此时未与操作系统底层线程关联 可运行 调用了 start 方法就会由新建进入可运行此时与底层线程关联由操作系统调度执行 终结 线程内代码已经执行完毕由可运行进入终结此时会取消与底层线程关联 阻塞 当获取锁失败后由可运行进入 Monitor 的阻塞队列阻塞此时不占用 cpu 时间当持锁线程释放锁时会按照一定规则唤醒阻塞队列中的阻塞线程唤醒后的线程进入可运行状态 等待 当获取锁成功后但由于条件不满足调用了 wait() 方法此时从可运行状态释放锁进入 Monitor 等待集合等待同样不占用 cpu 时间当其它持锁线程调用 notify() 或 notifyAll() 方法会按照一定规则唤醒等待集合中的等待线程恢复为可运行状态 有时限等待 当获取锁成功后但由于条件不满足调用了 wait(long) 方法此时从可运行状态释放锁进入 Monitor 等待集合进行有时限等待同样不占用 cpu 时间当其它持锁线程调用 notify() 或 notifyAll() 方法会按照一定规则唤醒等待集合中的有时限等待线程恢复为可运行状态并重新去竞争锁如果等待超时也会从有时限等待状态恢复为可运行状态并重新去竞争锁还有一种情况是调用 sleep(long) 方法也会从可运行状态进入有时限等待状态但与 Monitor 无关不需要主动唤醒超时时间到自然恢复为可运行状态
死锁
多个线程被阻塞他们中的一个或多个线程都在等待某个资源被释放从而造成无限期的阻塞
预防死锁
破坏请求并保持条件一次性申请所有的资源破坏不剥夺条件占用部分资源的线程进一步申请其他资源时如果申请不到可以主动释放它占有的资源。破坏循环等待条件靠按序申请资源来预防。按某一顺序申请资源释放资源则反序释放。
避免死锁
银行家算法
wait 和 sleep 方法的不同
wait是Object的方法sleep是Thread的方法wait会释放锁sleep不会释放锁wait必须在同步代码块中使用sleep可以在任何地方使用wait不需要捕获异常sleep必须要捕获异常
sleep与yield方法的不同
sleep方法给其他线程运行机会时不会考虑线程优先级yield方法只会给相同或更高优先级的线程运行机会线程执行sleep方法后进入超时等待状态执行yield方法后转入就绪状态sleep方法声明会抛出异常yield方法声明不会抛出异常sleep方法中需要指定时间参数yield方法不需要受jvm控制
synchronized关键字
作用
原子性一个或多个操作要么全部执行成功要么全部执行失败。synchronized关键字可以保证只有一个线程拿到锁访问共享资源。可见性当一个线程对共享变量进行修改后其他线程可以立刻看到。执行synchronized时会对应执行 lock、unlock原子操作保证可见性。有序性程序的执行顺序会按照代码的先后顺序执行
用法
修饰普通方法修饰静态方法指定对象修饰代码块
特点
阻塞未获的锁、竞争同一个对象锁的线程获取锁无法设置超时非公平锁、悲观锁、可重入锁、独占锁控制等待和唤醒需要结合加锁对象的wait(), notify(),notifyAll()方法锁的功能是JVM层面实现的加锁代码块执行完毕或执行过程中出现异常会自动释放锁
原理
同步方法通过加ACC_SYNCHRONIZED标识实现线程执行权的控制同步代码块是通过monitorenter和monitorexit指令获取线程的执行权
BlockingQueue
父类Collection
实现类ArrayBlockingQueue、LinkedBlockingQueue Semphore
acquirerelease
线程池
三大方法
newSingleThreadExecutornewFixedThreadPoolnewCachedThreadPool
七大参数 核心线程数 最大线程数核心线程数工作队列大小 生存时间 时间单位 工作队列 线程工厂 拒绝策略
四大拒绝策略
1.AbortPolicy直接抛出异常默认策略
2.CallerRunsPolicy用调用者所在的线程来执行任务
3.DiscardOldestPolicy丢弃阻塞队列中靠最前的任务并执行当前任务
4.DiscardPolicy直接丢弃任务
确定线程池的核心线程数
IO密集型任务
一般来说文件读写、DB读写、网络请求等
推荐核心线程数大小设置为2N1 N为计算机的CPU核数
CPU密集型任务
一般来说计算型代码、Bitmap转换、Gson转换等
推荐核心线程数大小设置为N1 N为计算机的CPU核数
//获取CPU核数
Runtime().getRuntime().availableProcessors();四大函数式接口 函数式接口接口中只有一个抽象方法 使用Lamda表达式进行简化 Function函数型接口有传入值有返回值 FunctionString,String functioni-{return i};
function.apply(hello);Predicate判断型接口 有传入值返回一个bool类型
PredicateString predicatei-{return i.empty();};
predicate.test(hi);Consumer消费型接口有传入值没有返回值
ConsumerString consumeri-{System.out.println(i);};
consumer.accept(a); Supplier供给型接口无传入值有返回值 SupplierString supplier()-{return hi}
supplier.get();JMMJava内存模型
是jvm规范中所定义的一种内存模型。围绕着原子性、可见性、有序性三个特征建立起来的。
关于JMM的一些同步的约定 1、线程解锁前必须把共享变量立刻刷回主存。 2、线程加锁前必须读取主存中的最新值到工作内存中 3、加锁和解锁是同一把锁
八种内存交互操作
lock锁定作用于主内存read读取作用于主内存load加载作用于工作内存use使用作用于工作内存assign赋值作用于工作内存store存储作用于工作内存write写入作用于主内存unlock解锁作用于主内存
JMM对八种内存交互操作的规定
不允许read、load、store、write操作之一单独出现也就是read操作后必须loadstore操作后必须write。不允许线程丢弃他最近的assign操作即工作内存中的变量数据改变了之后必须告知主存。不允许线程将没有assign的数据从工作内存同步到主内存。一个新的变量必须在主内存中诞生不允许工作内存直接使用一个未被初始化的变量。就是对变量实施use、store操作之前必须经过load和assign操作。一个变量同一时间只能有一个线程对其进行lock操作。多次lock之后必须执行相同次数unlock才可以解锁。如果对一个变量进行lock操作会清空所有工作内存中此变量的值。在执行引擎使用这个变量前必须重新load或assign操作初始化变量的值。如果一个变量没有被lock就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量。一个线程对一个变量进行unlock操作之前必须先把此变量同步回主内存。
volatile
保证可见性不保证原子性禁止CPU进行指令重排序
CAS
compareandSet是一种乐观锁的思想在不加锁的情况下可以保证线程操作共享资源的原子性利用了自旋锁底层依赖于Unsafe类直接去操作内存。Unsafe类中都是native修饰的方法。CAS操作包含三个操作数内存值V期望值A新值B。若内存中的值与期望值一样则将内存中的值更新为新值B。缺点导致ABA问题(狸猫换太子) ABA:如果一个线程t1正修改共享变量的值A但还没修改此时另一个线程t2获取到CPU时间片将共享变量的值A修改为B然后又修改为A此时线程t1检查发现共享变量的值没有发生变化但是实际上却变化了。解决办法AutomicStampedReferenceCompareAndSet方法会判断当前的引用是否等于预期引用再判断当前版本号是否跟原来的一致全部相等才更新值。
自旋锁
循环加锁 - 等待的机制
优点减少上下文切换的消耗
缺点循环占有浪费CPU资源
乐观锁与悲观锁
乐观锁不怕别的线程来修改共享变量如CAS适合读操作多的场景悲观锁防止其他线程来修改共享变量有上锁、解锁的操作如synchronized适合写操作多的场景
独享锁与共享锁
独享锁一次只能被一个线程持有如SynchronizedReentrantLock共享锁一次可以被多个线程持有如ReadWriteLock中返回的ReadLock
AQS
AQS是一个Java线程同步的框架是JDK中多锁工具的核心实现框架AQS中维护了一个信号量state和一个由线程组成的双向链表队列。在可重入的这个场景下state用来表示加锁的次数0表示无锁每加一次锁state就加1释放锁就减1
可重入锁ReentrantLock 可重入就是说某个线程已经获得某个锁可以再次获取锁而不会出死锁 相较于synchronized 特点 可以设置超时时间可中断可设置公平锁 实现原理CASAQS
synchronized与ReentrantLock的区别
synchronized是非公平锁ReentrantLock可以设置公平锁ReentrantLock可以设置超时时间synchronized竞争锁时会一直等待ReentrantLock可以尝试获取锁并得到获取结果锁等待和唤醒的方式不同synchronized使用waitnotifynotifyAll方法ReentrantLock使用Condition的awaitsignalsignalAll方法synchronized是JVM层面实现的ReentrantLock是基于JDK代码层面实现的synchronized的加锁、释放锁是自动的而ReentrantLock需要手动设置
单例模式
饿汉式
/*** 饿汉式单例*/
public class Hungry {/*** 可能会浪费空间private byte[] data1new byte[1024*1024];private byte[] data2new byte[1024*1024];private byte[] data3new byte[1024*1024];private byte[] data4new byte[1024*1024];private Hungry(){}private final static Hungry hungry new Hungry();public static Hungry getInstance(){return hungry;}}
懒汉式DCL
//懒汉式单例模式
public class LazyMan {private static boolean key false;private LazyMan(){synchronized (LazyMan.class){if (keyfalse){keytrue;}else{throw new RuntimeException(不要试图使用反射破坏异常);}}System.out.println(Thread.currentThread().getName() ok);}private volatile static LazyMan lazyMan;//双重检测锁模式 简称DCL懒汉式public static LazyMan getInstance(){//需要加锁if(lazyMannull){synchronized (LazyMan.class){if(lazyMannull){lazyMannew LazyMan();/*** 1、分配内存空间* 2、执行构造方法初始化对象* 3、把这个对象指向这个空间** 就有可能出现指令重排问题* 比如执行的顺序是1 3 2 等* 我们就可以添加volatile保证指令重排问题*/}}}return lazyMan;}//单线程下 是ok的//但是如果是并发的public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {//Java中有反射
// LazyMan instance LazyMan.getInstance();Field key LazyMan.class.getDeclaredField(key);key.setAccessible(true);ConstructorLazyMan declaredConstructor LazyMan.class.getDeclaredConstructor(null);declaredConstructor.setAccessible(true); //无视了私有的构造器LazyMan lazyMan1 declaredConstructor.newInstance();key.set(lazyMan1,false);LazyMan instance declaredConstructor.newInstance();System.out.println(instance);System.out.println(lazyMan1);System.out.println(instance lazyMan1);}
}
静态内部类
//静态内部类
public class Holder {private Holder(){}public static Holder getInstance(){return InnerClass.holder;}public static class InnerClass{private static final Holder holder new Holder();}
}
反射导致单例不安全
枚举
//enum 是什么 enum本身就是一个Class 类
public enum EnumSingle {INSTANCE;public EnumSingle getInstance(){return INSTANCE;}
}class Test{public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {EnumSingle instance1 EnumSingle.INSTANCE;ConstructorEnumSingle declaredConstructor EnumSingle.class.getDeclaredConstructor(String.class,int.class);declaredConstructor.setAccessible(true);//java.lang.NoSuchMethodException: com.ogj.single.EnumSingle.init()EnumSingle instance2 declaredConstructor.newInstance();System.out.println(instance1);System.out.println(instance2);}
}
使用枚举我们就可以防止反射破坏了。
反编译源码
//enum 是什么 enum本身就是一个Class 类
public enum EnumSingle {INSTANCE;public EnumSingle getInstance(){return INSTANCE;}
}class Test{public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {EnumSingle instance1 EnumSingle.INSTANCE;ConstructorEnumSingle declaredConstructor EnumSingle.class.getDeclaredConstructor(String.class,int.class);declaredConstructor.setAccessible(true);//java.lang.NoSuchMethodException: com.ogj.single.EnumSingle.init()EnumSingle instance2 declaredConstructor.newInstance();System.out.println(instance1);System.out.println(instance2);}
}
ConcurrentHashMap
1.7中底层采用分段的数组链表1.8中底层采用数组链表/红黑树CASSynchronized来保证并发安全
ThreadLocal
ThreadLocal为每个线程都分配一个独立的线程副本从而解决了变量并发访问冲突的问题。ThreadLocal 同时实现了线程内的资源共享。
三个主要方法
set(value) 设置值get() 获取值remove() 清除值
在使用ThreadLocal的时候强烈建议务必手动remove
Mysql
索引底层
索引是帮助Mysql高效获取数据的数据结构MySQL的默认存储引擎InnoDB采用B树来存储索引。 B树阶数更多路径更短 磁盘读写代价地非叶子节点存储指针只有叶子结点才存储数据。 B树方便扫库和区间查询
聚簇索引和非聚簇索引二级索引
根据该索引可以查出一行数据所有列非聚簇索引只能查出主键然后再根据主键查出一行数据回表查询
回表查询
通过二级索引找出对应的主键再通过主键找到聚集索引中对应的整行数据这个过程就是回表。
覆盖索引
覆盖索引指列所有返回值都可以通过该索引查到
索引失效的几种情况
违反联合索引的最左前缀原则模糊查询时%出现在左侧like %or连接的条件两侧中有一侧没有建立索引对添加了索引的字段进行运算或者类型转换 最左前缀法则查询从索引的最左列开始并且不跳过索引中的列。若跳跃了某一列后面的字段索引失效 事务的特性
A 原子性C 一致性I 隔离性D 持久性
并发事务带来的问题
读脏数据 一个事务对数据进行了修改修改的数据还没写入到数据库中这时另一个事务也访问了这条数据这条数据为脏数据读脏数据不可重复读 一个事务A多次读取同一数据另一事务B也访问该数据在A读数据的间隙中B的修改导致A两次读到的数据可能不太一样。幻读 事务A读取了几行数据事务B插入了一些数据。在随后的查询中事务A发现了一些原本不存在的数据就像发生了幻觉。
如何解决并发事务带来的问题事务隔离级别
未提交读read uncommitted什么都解决不了提交读read committed解决脏读重复读repeatable read默认隔离级别解决脏读、不可重复读串行化serializable解决脏读、不可重复读、幻读但性能比较低
redo log 和 undo log
redo log日志记录的是数据页的物理变化服务宕机可用来同步数据undo log 主要记录的是逻辑日志当事务回滚时通过逆操作恢复原来的数据比如我们删除一条数据的时候就会在undo log日志文件中新增一条delete语句如果发生回滚就执行逆操作
redo log保证了事务的持久性undo log保证了事务的原子性和一致性
MVCC 事务隔离通过加锁和MVCC实现的 mvcc的意思是多版本并发控制。指维护一个数据的多个版本使得读写操作没有冲突它的底层实现主要是分为了三个部分隐藏字段undo log日志readView读视图. 隐藏字段是指在mysql中给每个表都设置了隐藏字段有一个是trx_id(事务id)记录每一次操作的事务id是自增的另一个字段是roll_pointer(回滚指针)指向上一个版本的事务版本记录地址 undo log主要的作用是记录回滚日志存储老版本数据在内部会形成一个版本链在多个事务并行操作某一行记录记录不同事务修改数据的版本通过roll_pointer指针形成一个链表 readView解决的是一个事务查询选择版本的问题在内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据不同的隔离级别快照读是不一样的最终的访问的结果不一样。如果是rc(read commited)隔离级别每一次执行快照读时生成ReadView如果是rr(repead read)隔离级别仅在事务中第一次执行快照读时生成ReadView后续复用
主从同步原理 MySQL主从复制的核心就是二进制日志BINLOG它记录了所有的DDL(数据定义语言)和DML数据操纵语言不包括SELECT,SHOW. 主库在提交事务会把数据变更记录到binlog中从库读取主库的binlog文件写入到从库的中继日志relaylog中从库重做relaylog中的事件将改变自己的数据
分库分表
作用分担访问压力解决存储压力 垂直分库以表为依据根据业务将不同表分到不同库中 提高IO 垂直分表以字段为依据根据字段属性将不同字段分到不同表中 冷热数据分离 水平分库将一个库的数据分到不同库中 abcabc 提高系统的稳定性和可用性 水平分表将一个表的数据拆分到多个表中可以在同一个库中 优化单一表数据量过大产生的性能问题