Callable
public class CallableDemo {
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
class a implements Callable<String> {
@Override
public String call() throws Exception {
// 相对于runnable接口这个接口不但有返回值,还可以抛异常
return null;
}
}
线程池
线程池的优势:所有池化技术。最开始cpu是单核,所以并不是真正的多线程,而现在是真正的多线程,减少了上下文的切换。上下文切换的理解,就是可能cpu为了让用户感觉不到是一个单核所以他要疲于切换,这就是产生了消耗。从javase阶段我们是需要什么对象就new什么对象,或者通过api获取该对象的实例。而到了ee阶段通过spring的控制反转,交给spring管理,需要什么对象就找spring要,而线程池也是一样,之前需要创建多线程就new,现在直接从池子里要。ThreadPoolExecutor。
而线程池底层都是new了一个ThreadPoolExecutor的类,而且也用到了阻塞队列,LinkedBlockingQueue或者syn的queue。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author Jing
* @date 2020/10/6 0006 15:22
*/
public class ThreadPoolDemo {
public static void main(String[] args) {
// 创建一个线程池 里面是只有一个线程的线程池,
ExecutorService executor = Executors.newSingleThreadExecutor();
// 创建一个线程池 里面是只有N个线程的线程池,这个N不确定由内部自己控制
ExecutorService executor1 = Executors.newCachedThreadPool();
// 创建一个线程池 里面是只有参数个个线程的线程池,
ExecutorService executor2 = Executors.newFixedThreadPool(5);
// 使用
try {
for (int i = 0; i < 10; i++) {
executor2.execute(() -> {
System.out.println(Thread.currentThread().getName()+"执行任务");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭线程池
executor2.shutdown();
}
}
}
线程池的七大参数介绍:
阳哥这个图还是比较有牌面的,首先第一个参数就是常驻核心线程数,如果把整个线程池比作银行的一家网点的话,那么核心常驻线程数就是网点当日的值班窗口,也就是1和2.如果常驻线程数的线程满足不了需求,意思是需要有个地方给新来的线程,如果是在银行网点的话可能会有一个候客区,有椅子可以坐,那么对应线程池来说就是有一个阻塞队列,这个队列肯定也有一个规模,当队列里的线程又满了之后怎么处理呢?以银行为例,他可能会多开放一些值班窗口,线程池也是如此,直接开启到最大线程数,而此时又来了新的线程,这时候和银行略有不同,按理说银行新顾客来了不管之前怎么样,都应该排在前面顾客的后面,而线程池不是,他直接可以去新开放的窗口去执行任务,有一些抢占式的味道,估计是感觉等候区的拿出来在过去的时间不如直接新人过去快才这么设计的。之后如果客流慢慢减少了,到某一个值之后会从最大线程数降到核心常驻线程数,最后一个参数就是拒绝策略,如果还不行就要拒绝掉任务,这里有好几种的拒绝策略,而还有一个没什么卵用的参数就是设置这个线程池的一些信息???阳哥这么讲的。就像你这是哪一家银行的网点呀,总要有个地方可以设置。下面这个图可以理解一下线程池的工作原理
第一就是直接报异常,第二种是回退给调用者,可以理解为main。第三种是抛弃最久,第四种是抛弃这个任务。
为什么工作中以上三种都不用?因为默认的最大值都是21yi,就是那个最大的线程数量,这会导致堆积。然后OOM。
线程池的合理参数怎么选择:::::
分两种情况考虑。如果是cpu密集型 cpu + 1
如果是IO密集型就是cpu核心数*2 cpu / 1- 阻塞系数 基本就是十倍,因为IO密集型就是cpu在闲置中。
死锁的检测
import java.util.concurrent.TimeUnit;
/**
* @author Jing
* @date 2020/10/6 0006 17:37
* 死锁代码
*/
public class DieLockDemo {
public static void main(String[] args) {
String a = "a";
String b = "b";
Source2 source2 = new Source2(a, b);
Source2 source21 = new Source2(b, a);
// new Thread(new Runnable() {
// @Override
// public void run() {
// try {
// source2.run();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }).start();
// new Thread(new Runnable() {
// @Override
// public void run() {
// try {
// source21.run();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }).start();
new Thread(new Source1(a,b)).start();
new Thread(new Source1(b,a)).start();
}
}
class Source1 implements Runnable{
String LockA;
String LockB;
public Source1(String lockA, String lockB) {
LockA = lockA;
LockB = lockB;
}
public void run(){
synchronized (LockA){
System.out.println("我拿到了"+LockA);
synchronized (LockB){
System.out.println("我想要"+LockB);
}
}
}
}
class Source2 {
String LockA;
String LockB;
public Source2(String lockA, String lockB) {
LockA = lockA;
LockB = lockB;
}
public void run() throws InterruptedException {
synchronized (LockA){
System.out.println("我拿到了"+LockA);
TimeUnit.SECONDS.sleep(1);
synchronized (LockB){
System.out.println("我想要"+LockB);
}
}
}
}