线程、进程
线程:是进程的一个执行单元,是CPU执行的最小单位;
进程:运行中的程序是计算机分配内存资源的最小单位。
创建线程方式
线程常用方法
run() yield() wait()
start() sleep() notify()
join()
线程的状态
新建、就绪、运行、阻塞、死亡
多线程的安全问题
多线程不一定有问题,共享操作是有问题的
解决方案
加锁;排队;并发执行;一个一个执行
加锁方式
synchronized关键字+同步对象(对多个线程来说是同一个对象):
可以添加在代码上
synchronized(同步锁/同步对象){
}
还可以加在方法上, 同步不需要我们提供了,静态方法,锁是类的Class对象,非静态方法,锁是this。
ReentrantLock实现了Lock接口,所以可以称为lock锁,
实现原理不同:
ReentrantLock是一种java代码层面的控制实现 ,而synchronized是关键字,依靠的是底层编译后的指令实现
加锁范围不同:
ReentrantLock只能对某一段代码块加锁,而synchronized可以对代码块和方法加锁
加锁释放锁方式不同:
ReentrantLock需要手动的加锁释放锁,而synchronized是隐式的自动的加锁,自动释放锁(代码执行完了,出现异常了)
线程死锁
指俩个或多个线程,分别持有对方需要的资源,相互僵持等待。
死锁条件:
线程通信
同步情况下 、notify()、wait()
围绕着线程安全问题,用户在手机上买票,抢购,秒杀
优点:提高程序的响应速度,可以多个线程完成自己的工作,提高硬件设备的利用率
缺点:可能会出现资源争夺问题
并发执行:在一段时间内,多个线程依次执行
并行执行:真正意义上的同时执行,俩个线程在同一个时间点上一起执行
高并发指的是很多用户一起访问
不可见性:一个线程对共享变量的修改,另外一个线程不能够立刻看到
由于想让程序响应处理速度更快, java内存模型设计有主内存和工作内存(线程使用的内存)。线程中不能直接对主内存中的数据进行操作,必须将主内存数据加载到工作内存(本地内存), 这样在多核cpu下就会产生不可见性。
乱序性:指令在执行过程中,为了优化性能,可能将一些语句的顺序改变。
volatile
可以解决不可见性, volatile修饰的变量在一个线程修改后,对其他线程立即可见,还可以解决乱序性, volatile修饰的变量在执行时禁止指令重排序,但是不能解决非原子性问题。
非原子性:线程切换带来的非原子性问题,A先执行被B插了一脚。
原子性:一个或多个操作在 CPU 执行的过程中不被中断的特性
措施:
AQS:抽象同步队列是一个底层具体的同步实现者。
AbstractQueuedSynchronizer类中有一个int类型state变量,记录锁的状态
volatile int state; //标记有没有线程在访问共享资源
内部类
static final class Node{
volatile Node prev;
volatile Node next;
volatile Thread thread;
}
protected final int getState() {
return state;
}
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
ReentrantLock源码:
abstract static class Sync extends AbstractQueuedSynchronizer {
lock();
unlock();
}
static final class NonfairSync extends Sync {
实现加锁
final void lock() {
if (compareAndSetState(0, 1)) //先尝试获取锁,修改锁的状态
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
}
static final class FairSync extends Sync {
final void lock() {
acquire(1); //走正常流程获取锁, 如果当前锁状态为0,获取锁,状态改为1
如果当前锁状态为1,把线程放入到队列
}
}
无参构造方法
public ReentrantLock() {
sync = new NonfairSync(); //使用的是非公平锁
}
有参构造方法
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();//FairSync公平锁,NonfairSync非公平锁
}
List
允许一个线程等待其他线程执行完毕后再执行,创建CountDown Latch对象时指定一个初始值是线程数量,执行完一个,AQS内部state-1,当state为0表示所有线程执行完毕,然后等待的线程就可以工作了
池(容器 集合 ArrayList): 每次连接数据库都要创建一个连接对象,用完之后就销毁了,频繁创建和销毁占用一定的开销。 可以创建出一定数量的连接对象放到池子中, 有连接到来时,从池子中获得一个连接对象使用,用完之后不销毁,还回到池子中即可,减少创建销毁的开销。
数据库的连接池
线程池:频繁的创建线程,销毁线程也是需要开销的。
有两个类实现线程池:
ThreadPoolExecutor
Executors
其中阿里巴巴开发规约中规定使用ThreadPoolExecutor实现
ThreadPoolExecutor中可以准确的控制创建的数量,最大等待数量,拒绝策略等
ThreadPoolExecutor构造方法中的7个参数: