Java创建线程的4中方式:
继承Thread类:浪费仅有的一次继承机会实现Runnable接口:无返回值实现Callable接口:可以有返回值,可抛出异常,可中断通过线程池创建:线程复用,但是实际开发中应该自己实现线程池相对于Runnable接口而言,Callable接口的优势在于:
判断线程任务是否完成或者被取消能够中断任务能够获得返回结果,且可以抛出异常线程池做的工作主要是控制运行的线程的数量,处理过程中将任务加入队列,然后在线程创建后启动这些任务。如果先生超过了最大数量,超出的数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
主要特点为:
线程复用;控制最大并发数;管理线程。优势为: 4. 降低资源消耗.通过重复利用自己创建的线程降低线程创建和销毁造成的消耗。 5. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能执行; 6. 提高线程的可管理性。
Java中的线程池是通过Executor框架实现的,该框架中用到了Executor, Executors, ExecutorService, ThreadPoolExecutor 这几个类。
ThreadPoolExecutor 是主要线程池类的父类。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 1. corePoolSize:线程池中的常驻核心线程数 2. maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值大于等于1 3. keepAliveTime:多余的空闲线程存活时间,当空间时间达到keepAliveTime值时,多余的线程会被销毁直到只剩下corePoolSize个线程为止 4. unit:keepAliveTime的单位 5. workQueue:任务队列,被提交但尚未被执行的任务. 6. threadFactory:表示生成线程池中工作线程的线程工厂,用户创建新线程,一般用默认即可 7. handler:拒绝策略,表示当线程队列满了并且工作线程大于等于线程池的最大显示 数(maxnumPoolSize)时如何来拒绝. corePoolSize 在创建了线程池后,当有请求任务来之后,就会安排池中的线程去执行请求任务,近视理解为今日当值线程当线程池中的线程数目达到corePoolSize后,就会把到达的任务放入到缓存队列当中. keepAliveTime 只有当线程池中的线程数大于corePoolSize时keepAliveTime才会起作用,直到线程中的线程数不大于corepoolSIze。阻塞队列也已经排满了,再也塞不下新的任务了。同时, 线程池的 max 也到达了,无法接续为新任务服务 这时我们需要拒绝策略机制合理的处理这个问题。
AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行CallerRunsPolicy:调用者运行的一种机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入到队列中尝试再次提交当前任务DiscardPolicy:直接丢弃任务,不予任何处理也不抛出异常。如果任务允许丢失,那么该策略是最好的方案注意
以上4种拒绝策略均实现了RejectedExecutionHandler接口
在实际开发中不允许使用内置的线程池:必须明确地通过ThreadPoolExecutor 方式,指定相应的线程池参数创建自定义线程或者使用其它框架提供的线程池。因为内置线程池的第五个参数阻塞队列允许的请求队列长度为 Integer.MAX_VALUE,可能造成大量请求堆积,导致OOM:
自构造线程池 public static void main(String[] args) { ExecutorService threadPool = new ThreadPoolExecutor( 2, 5, 1L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy() ); try { for (int i = 1; i <= 10; i++) { threadPool.execute(() -> { System.out.println(Thread.currentThread().getName() + "\t 办理业务"); }); } }catch (Exception e){ e.printStackTrace(); }finally { threadPool.shutdown(); } }两个及以上的线程在执行过程中,因为互相争夺资源而造成一种相互等待的现象,如果外力干涉,那么它们都将无法推进下去。
死锁产生的一般原因包括:
系统资源不足进程运行推进的顺序不合适资源分配不当 死锁演示代码 public class DeadLockDemo { public static void main(String[] args) { String lockA = "lockA"; String lockB = "lockB"; new Thread(new HoldLockThread(lockA,lockB),"ThreadAAA").start(); new Thread(new HoldLockThread(lockB,lockA),"ThreadBBB").start(); } } class HoldLockThread implements Runnable{ private String lockA; private String lockB; public HoldLockThread(String lockA, String lockB) { this.lockA = lockA; this.lockB = lockB; } @Override public void run() { synchronized (lockA){ System.out.println(Thread.currentThread().getName()+"\t自己持有:"+lockA+"\t尝试获得:"+lockB); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockB){ System.out.println(Thread.currentThread().getName()+"\t自己持有:"+lockB+"\t尝试获得:"+lockA); } } } } # 对进程进行分析,可以得知,这个程序发生了 deadlock。 D:\projects\java-simple\src\main\java\com\atLearn>jps 39536 RemoteMavenServer36 35908 DeadLockDemo 36164 Jps 38184 39372 Launcher D:\projects\java-simple\src\main\java\com\atLearn>jstack 35908 2020-07-04 01:15:23 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode): ============================= "ThreadBBB": waiting to lock monitor 0x000000001c6c0528 (object 0x000000076b51a9d8, a java.lang.String), which is held by "ThreadAAA" "ThreadAAA": waiting to lock monitor 0x000000001c6c2ba8 (object 0x000000076b51aa10, a java.lang.String), which is held by "ThreadBBB" Java stack information for the threads listed above: =================================================== "ThreadBBB": at com.atLearn.HoldLockThread.run(DeadLockDemo.java:39) - waiting to lock <0x000000076b51a9d8> (a java.lang.String) - locked <0x000000076b51aa10> (a java.lang.String) at java.lang.Thread.run(Thread.java:748) "ThreadAAA": at com.atLearn.HoldLockThread.run(DeadLockDemo.java:39) - waiting to lock <0x000000076b51aa10> (a java.lang.String) - locked <0x000000076b51a9d8> (a java.lang.String) at java.lang.Thread.run(Thread.java:748) Found 1 deadlock.