多线程专题
多线程
线程的 5 个状态的理解:
1. 新建,刚刚新建的线程,还未进入就绪队列
2. 就绪,进入就绪队列的线程拥有了获得 CPU 时间的机会,但不是一定会马上执行,与线程调度有关。
3. 运行,获得了 CPU 时间,正在被执行的线程。
4. 阻塞,进入阻塞状态的线程只是暂时失去了 CPU 时间,该类线程没有结束,“阻塞态”的线程只能进入到“就绪态”。
5. 死亡,死亡的线程即彻底结束了。
问题:
1.并行和并发有什么区别?
并行是真的同时执行,多台cpu同时执行;并发是假的同时,本质上是一台cpu快速切换。
2.线程和进程的区别?
进程是线程的容器,进程包含线程
3.创建线程有哪几种方式?
(1)继承Thread类,比如myThread继承Thread, Thread myThread = new MyThread();
(2)实现Runnable接口,比如MyRunnable implement Runnable,Thread myThread = new Thread(new MyRunnable());
(3) 实现Callable接口,比如MyCallable implement Callable, Thread myThread = new Thread(new FetureTask<>(new MyCallable()));
4.说一下 Runnable 和 Callable 有什么区别?
(1)Callable可以获取返回值,通过FetureTask.get()方法获取,Runnable不能获取返回值;
(2)Callable可以往外抛出异常,Runnable不能抛出异常,只能内部消化
5.sleep() 和 wait() 有什么区别?
(1)sleep是Thread类的方法,可以任意地方使用;wait是Object类的方法,只能用在同步代码块中,因为:
(2)sleep不释放锁,wait释放锁,举例:
public class MyThread extends Thread{ private static Object locker = new Object(); @Override public void run() { synchronized (locker){ System.out.println("wait start"); try { // locker.wait(); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("wait end"); } } private void doNotify(){ synchronized (locker){ System.out.println("notify start"); locker.notify(); System.out.println("notify end"); } } public static void main(String[] args) throws InterruptedException { Thread td = new MyThread(); td.start(); Thread.sleep(2000); ((MyThread) td).doNotify(); } }

6.notify()和 notifyAll()有什么区别?
7.线程的 run()和 start()有什么区别?
start()方法会启动一个线程,直接调用run()方法不会启动线程,只在当前线程中继续调用Thread的run方法。
8.创建线程池有哪几种方式?
(1)通过Executors方式创建线程池
public class TestThreadPoolExecutors { public static void main(String[] args) { //单个任务的线程池 ExecutorService ex = Executors.newSingleThreadExecutor(); for (int i=0;i<10;i++) { ex.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在执行任务"); } }); } //固定任务的线程池 ExecutorService ex2 = Executors.newFixedThreadPool(5); for(int j=0;j<10;j++){ ex2.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在执行任务"); } }); } //可以变化数量的线程池 ExecutorService ex3 = Executors.newCachedThreadPool(); for(int j=0;j<20;j++){ ex3.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在执行任务"); } }); } //定时的单个任务的线程池 ScheduledExecutorService ex5 = Executors.newSingleThreadScheduledExecutor(); System.out.println("时间:" + System.currentTimeMillis()); for(int j=0;j<5;j++){ ex5.schedule(new Runnable() { @Override public void run() { System.out.println("时间:"+System.currentTimeMillis()+"--"+Thread.currentThread().getName() + "正在执行任务"); } },3, TimeUnit.SECONDS); } //定时的固定任务的线程池 ScheduledExecutorService ex4 = Executors.newScheduledThreadPool(2); System.out.println("时间:" + System.currentTimeMillis()); for(int j=0;j<5;j++){ ex4.schedule(new Runnable() { @Override public void run() { System.out.println("时间:"+System.currentTimeMillis()+"--"+Thread.currentThread().getName() + "正在执行任务"); } },3, TimeUnit.SECONDS); } } }
(2)通过ThreadPoolExecutor创建
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 10, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<>(5)); for (int i=0;i<10;i++) { poolExecutor.execute(new Runnable() { @Override public void run() { System.out.println("时间:"+System.currentTimeMillis()+"--"+Thread.currentThread().getName() + "正在执行任务"); } }); } poolExecutor.shutdown();
corePoolSize:线程池基本大小,当队列任务满了,才会创建超出基本大小的线程。
maximumPoolSize:最大线程池大小,
9.线程池都有哪些状态?

Running:处理线程池和队列里等待的任务,接收新任务
ShutDown:处理线程池里和队列里等待的任务,不接受新任务;当线程池里和队列里的任务都执行完,转到Tidying状态
Stop:尝试停止线程池里的任务,不处理队列里等待的任务,不接受任务;当线程池里的任务执行完,转到Tidying状态
Tidying:执行terminated方法,执行完terminated()方法,由Tidying转为Terminated状态;
Terminated:线程池彻底停止
10.线程池中 submit()和 execute()方法有什么区别?
submit有返回值,execute没有,所以submit可以接受Callable实现类,execute不行,因为Callable是有返回值的
两者都可以接收FutureTask,Runnable实现类
ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 7, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<>()); for (int i = 0; i < 10; i++) { FutureTask futureTask = new FutureTask<Integer>(new Callable<Integer>() { @Override public Integer call() throws Exception { return 3; } }); executor.submit(futureTask);// 可以接受FutureTask executor.execute(futureTask);// 可以接受FutureTask System.out.println(futureTask.get()); } for (int i = 0; i < 10; i++) { executor.execute(new Runnable() { // execute没有返回值,execute不能接受Callable实现类 @Override public void run() { System.out.println(Thread.currentThread().getName()+" :is run"); } }); } for (int i = 0; i < 10; i++) { FutureTask futureTask = (FutureTask<Integer>) executor.submit(new Callable<Integer>(){// submit有返回值,能接受Callable实现类 @Override public Integer call() { System.out.println(Thread.currentThread().getName()+" :is run"); return 3; } }); }
11.线程池的工作流程

核心线程池没满,就创建新线程;满了就往队列添加;队列满了,再判断最大线程池满没满,没满继续创建线程,满了就执行线程饱和策略
12.在 java 程序中怎么保证多线程的运行安全?
13.线程池中队列的种类、原理与使用
(1)SynchronousQueue同步队列:直接提交的任务队列
(2)ArrayBlockingQueue有界队列:同限制长度的无界队列
(3)LinkBlockingQueue无界队列:限制长度就是有界队列,无界队列适用于短时间高并发的任务情景。
14.线程池的队列饱和策略
当最大线程池+队列的大小<任务数,会触发队列饱和策略;
Abort策略:默认策略,超过饱和度的任务提交时,抛出RejectedExecutionException(拒绝执行)异常,异常可由调用者捕获
CallerRuns策略: 回退超过饱和度的任务
Discard策略:抛弃超过饱和度的任务
DiscardOlds策略:抛弃队列中的任务,提交超过饱和度的新任务
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<>(5)); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 10; i++) { int count = i; FutureTask futureTask = (FutureTask<Integer>) executor.submit(new Callable<Integer>(){ @Override public Integer call(){ System.out.println(Thread.currentThread().getName()+";这是第"+count+"个任务"); return 3; } }); }

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<>(5)); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());//抛弃溢出的任务 for (int i = 0; i < 10; i++) { int count = i; FutureTask futureTask = (FutureTask<Integer>) executor.submit(new Callable<Integer>(){ @Override public Integer call(){ System.out.println(Thread.currentThread().getName()+";这是第"+count+"个任务"); return 3; } }); }
pool-1-thread-1;这是第0个任务
pool-1-thread-3;这是第7个任务
pool-1-thread-2;这是第1个任务
pool-1-thread-1;这是第2个任务
pool-1-thread-2;这是第3个任务
pool-1-thread-4;这是第8个任务
pool-1-thread-2;这是第6个任务
pool-1-thread-1;这是第5个任务
pool-1-thread-3;这是第4个任务
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<>(5)); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());//抛弃已存在的任务 for (int i = 0; i < 10; i++) { int count = i; FutureTask futureTask = (FutureTask<Integer>) executor.submit(new Callable<Integer>(){ @Override public Integer call(){ System.out.println(Thread.currentThread().getName()+";这是第"+count+"个任务"); return 3; } }); }
pool-1-thread-1;这是第0个任务
pool-1-thread-3;这是第7个任务
pool-1-thread-2;这是第1个任务
pool-1-thread-3;这是第3个任务
pool-1-thread-1;这是第4个任务
pool-1-thread-2;这是第5个任务
pool-1-thread-4;这是第8个任务
pool-1-thread-1;这是第9个任务
pool-1-thread-3;这是第6个任务
pool-1-thread-1;这是第0个任务
pool-1-thread-2;这是第1个任务
pool-1-thread-1;这是第2个任务
pool-1-thread-3;这是第7个任务
pool-1-thread-2;这是第4个任务
pool-1-thread-1;这是第5个任务
pool-1-thread-2;这是第9个任务
pool-1-thread-4;这是第8个任务
pool-1-thread-3;这是第6个任务
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<>(5));
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//回退溢出的任务
for (int i = 0; i < 10; i++) {
int count = i;
FutureTask futureTask = (FutureTask<Integer>) executor.submit(new Callable<Integer>(){
@Override
public Integer call(){
System.out.println(Thread.currentThread().getName()+";这是第"+count+"个任务");
return 3;
}
});
}
pool-1-thread-1;这是第0个任务
main;这是第9个任务
pool-1-thread-1;这是第2个任务
pool-1-thread-2;这是第1个任务
pool-1-thread-1;这是第3个任务
pool-1-thread-2;这是第4个任务
pool-1-thread-2;这是第6个任务
pool-1-thread-3;这是第7个任务
pool-1-thread-1;这是第5个任务
pool-1-thread-4;这是第8个任务
15.如果没达到核心线程的时候如果再有请求的时候为什么还会创建新线程
16.什么是死锁?

浙公网安备 33010602011771号