线程的概念:
线程是操作系统能进行的运算调度得到最小单位,被包含在进程中,是进程的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程可以并发多个线程,每个线程执行不同额任务
线程与进程的区别:
进程:系统中运行的一个应用程序,程序一旦运行就是进程,资源分配的最小单位
线程:系统分配处理器时间资源的基本单位,程序执行的最小单位
线程的状态:
NEW :创建状态
RUNNABLE: 运行状态
BLOCKED:阻塞状态
WAITING:等待状态
TIMED_WAITING:调用sleep()、join()、wait()方法可能导致线程处于等待状态
TERMINTED:执行完毕,退出
notify()和wait()的作用:
notify()唤醒一个正在等待这个对象的线程监控,如果有任何线程正在等待这个对象,那么它们中的一个被选择被唤醒,选择是任意的,需要在同步代码块或同步方法中调用,即调用前线程必须获得该对象的对象级别锁
wait()导致当前线程等待,直到另一个线程调用notify()或notifyAll()方法,属于Object类的方法,需要在同步代码块或同步方法中调用
wait和sleep的区别:
sleep和yield的异同:
相同:
sleep和yield都会释放CPU
不同:
sleep使当前线程进入停滞状态,执行sleep的线程在指定时间内不会执行,yield只是使当前线程重新回到可执行状态,执行yield有可能进入到可执行状态后马上又被执行,
死锁的概念:
死锁:指两个或多个进程或者线程在执行过程中因为争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态
死锁产生的四个必要条件(缺一不可)
并发与并行的区别:
并发:指在某个时间段内,多个任务交替执行任务,当多个线程在操作时,把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程运行时,其他线程处于挂起状态
并行:同一时刻同时处理多任务的能力,当多个线程在操作时,CPU同时处理这些线程请求的能力
主要区别在于CPU是否能同时处理所有任务,并发不能,并行能
线程安全的要素:
原子性:atomic包、cas算法、synchronized、lock
可见性:synchronized、volatile
有序性:happens-before规则
实现线程安全:
保证线程安全的机制:
synchronized关键字、lock锁、cas、volatile、Threadlocl等
创建线程的方法:
线程池创建:
线程池:线程存放的地方,目的是为了较少的系统开销
特点:
创建方式:
ThreadPoolExecutor介绍:
在这里插入代码片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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
TimeUnit.SECONDS
BlockingQueue:
阻塞队列,存在先进先出(FIFO)和先进后出(LIFO)两种
常见的有ArrayBlockingQueue\LinkedBlockingQueue
队列一端进入,一端输出,当队列满时阻塞。
核心方法:
ArrayBlockingQueue:
基于数组实现,内部维护一个定长的数组,以便缓存队列中的数据对象,除了定长的数据,内部还保存着2两个整形的变量,分别标识着队列的头部和尾部在数组中的位置。
LinkedBlockingQueue:
基于链表的阻塞队列,内部也维护了一个数据缓冲队列,如果没有指定其容量大小,他会默认一个无限大小的容量,这样一旦生产者的速度大于消费者速度,也许没有等到队列满阻塞系统内存就可能耗尽
区别:
handler拒绝策略:
JAVA提供四种丢弃处理方法,我们也可以实现接口RejectedExecutionHandler实现自己的策略
线程池的五种状态:
shutdownNow和shutdown的区别:
线程间通信的几种方式:
实现线程间通信的模型有两种:共享内存或者消息传递
题目:有A\B两个线程,A线程向一个集合循环添加字符串“123”,循环10次,当循环到第5次时,希望B线程收到A线程通知,然后开始B的业务
public class ThreadMsgTest {
//定义一个 volatile 属性的变量
private static volatile boolean flag = false;
private static void notifyThreadWithVolatile(){
Thread a = new Thread("线程A"){
@SneakyThrows
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (i == 5){
flag = true;
Thread.sleep(500);
break;
}
System.out.println(Thread.currentThread().getName() + "=====" + i);
}
}
};
Thread b = new Thread("线程B"){
@SneakyThrows
@Override
public void run() {
while (true){
while (flag){
System.out.println(Thread.currentThread().getName()+"收到通知");
System.out.println("开始处理业务");
Thread.sleep(1000);
}
}
}
};
a.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
b.start();
}
public static void main(String[] args) {
notifyThreadWithVolatile();
}
}