线程池
线程池状态
1.RUNNING
表示线程池正常运行,既能接受新任务,也会正常处理队列中的任务
2. SHUTDOWN
当调用线程池的shutdown()方法时,线程池就进入SHUTDOWN状态,表示线程池处于正在关闭状态,此状态下线程池不会接受新任务,但是会继续把队列中的任务处理完
3. STOP
当调用线程池的shutdownnow()方法时,线程池就进入STOP状态,表示线程池处于正在停止状态,此状态下线程池既不会接受新任务了,也不会处理队列中的任务,并且正在运行的线程也会被中断
4. TIDYING
线程池中没有线程在运行后,线程池的状态就会自动变为TIDYING,并且会调用terminated(),该方法是空方法,留给程序员进行扩展。
5.TERMINATED
terminated()方法执行完之后,线程池状态就会变为TERMINATED
创建线程执行任务
方法一:继承Thread类
public class test extends Thread {public static void main(String[] args) {test t = new test();t.start();}@Overridepublic void run() {System.out.println("hello");}
}
方法二:实现Runna接口
public class test implements Runnable{public static void main(String[] args) {Thread t=new Thread(new test());t.start();}@Overridepublic void run() {System.out.println("hello");}
}
方法三:实现Callable接口
public class test implements Callable<String> {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<String> futureTask = new FutureTask<>(new test());Thread thread = new Thread(futureTask);thread.start();String result = futureTask.get();System.out.println(result);}@Overridepublic String call() throws Exception {return "null";}
}
方法四:利用线程池来创建线程
public class test implements Runnable {public static void main(String[] args) {ExecutorService executorService= Executors.newFixedThreadPool(10);executorService.execute(new test());}@Overridepublic void run() {System.out.println("test");}
}
为什么不用Executors
发现创建的队列为LinkedBlockingQueue,是一个无界阻塞队列,如果使用该线程池执行任务,如果任务过多就会不断的添加到队列中,任务越多占用的内存就越多,最终可能耗尽内存,导致OOM。
Executors来创建线程池也不能自定义线程的名字,不利于排查问题,所以建议直接使用ThreadPoolExecutor来定义线程池,这样可以灵活控制。
ThreadLocal
ThreadLocal是Java中所提供的线程本地存储机制,可以利用该机制将数据缓存在某个线程内
部,该线程可以在任意时刻、任意方法中获取缓存的数据
实现原理
ThreadLocal底层是通过ThreadLocalMap来实现的,每个Thread对象中都存在一个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓存的值
应用场景
连接管理:一个线程持有一个连接(例如数据库连接),该连接对象可以在不同的方法之间进行传递,线程之间不共享同一个连接
内存泄漏
因为当ThreadLocal对象使用完之后,应该要把设置的key,value,也就是Entry对象进行回收,但线程池中的线程不会回收,而线程对象是通过强引用指向ThreadLocalMap,ThreadLocalMap也是通过强引用指向Entry对象,线程不被回收,Entry对象也就不会被回收,从而出现内存泄漏
解决办法:在使用了ThreadLocal对象之后,手动调用ThreadLocal的remove方法,手动清楚Entry对象