线程池
- 线程是宝贵的内存资源,单个线程占1MB空间,过多分配易造成内存溢出
- 频繁的创建及销毁线程会增加虚拟机回收频率、资源开销、造成程序性能下降
- 因此线程池出现了
线程池的概念
- 线程容器,可设定线程分配的数量上限
- 将预先创建的线程对象存入池中,并重用线程池中的线程对象
- 避免频繁的创建和销毁
线程池的原理
获取线程池
创建线程池
public class TestThreadPool { public static void main(String[] args) { // 1. 创建固定线程个数的线程池对象 //线程池里可存在4个线程 ExecutorService es = Executors.newFixedThreadPool(4); // 2. 创建任务 Runnable runnable = new Runnable() { private int ticket = 100; @Override public void run() { while (true) { if(ticket <= 0) { break; } System.out.println(Thread.currentThread().getName() + "买了" + ticket--); } } }; // 3. 提交任务 for(int i = 0; i < 5; i++) { es.submit(runnable); } // 4. 关闭线程池 es.shutdown(); }}
执行结果
注
// 1. 创建单线程的线程池 ExecutorService es = Executors.newSingleThreadExecutor();// 1. 创建缓冲线程池,线程的个数由任务来决定 ExecutorService es = Executors.newCachedThreadPool();
Callable接口
public interface Callable{ public V call() throws Exception;}
- JDK5加入,与Runnable接口类似,实现之后代表一个线程任务
- Callable具有泛型返回值、可以声明异常
Future接口
- 概念:异步接受ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值
- 方法:V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)
示例
- 使用Future和Callable接口
- 使用两个线程,并发计算1-50,51-100的和,再进行汇总
//示例public class TestCallable { public static void main(String[] args) throws Exception { // 1.创建线程池对象 ExecutorService es = Executors.newFixedThreadPool(2); // 2. 提交任务并得到Future对象,任务有Callable匿名对象来承担 Future future1 = es.submit(new Callable() { @Override public Integer call() throws Exception { //完成1-50的加和运算并得到结果 System.out.println("start 1-50 count..."); int sum = 0; for(int i = 1; i <= 50; i++) { sum += i; } return sum; } }); Future future2 = es.submit(new Callable() { @Override public Integer call() throws Exception { //完成51-100的加和运算并得到结果 System.out.println("start 51 - 100 count..."); int sum = 0; for(int i = 51; i <= 100; i++) { sum += i; } return sum; } }); // 3. 使用Future对象的get()方法得到运算结果 System.out.println("1-100的加和结果为:" + (future1.get() + future2.get())); // 4. 关闭资源 es.shutdown(); }}
结果
Lock接口
- JDK5加入,与synchronized比较,显示定义,结构更灵活
- 提供更多实用性方法,功能更加强大,性能更优越
常用方法
//获取锁,如锁被占用,则等待void lock() //尝试获取锁(成功true,失败false,不阻塞)boolean tryLock//释放锁void unlock()
//示例public class TestLock implements Runnable { Lock l = new ReentrantLock(); private int ticket = 100; @Override public void run() { while (true) { l.lock(); try { if(ticket <= 0) { break; } System.out.println(Thread.currentThread().getName() + " sells " + ticket--); } catch (Exception e) { e.printStackTrace(); }finally { l.unlock(); } } } public static void main(String[] args) { ExecutorService es = Executors.newFixedThreadPool(4); for(int i = 0; i < 4; i++) { es.submit(new TestLock()); } es.shutdown(); }}
执行结果
线程安全的集合
Collections中的工具方法
Queue接口(队列)
//示例public class TestQueue { public static void main(String[] args) { // 1. 创建PriorityQueue队列对象 PriorityQueue q = new PriorityQueue(); // 2. 队列添加元素,“入列” q.offer("a"); q.offer("b"); q.offer("c"); q.offer("d"); q.offer("e"); // 3. 取值,“出列” System.out.println(q.poll()); System.out.println(q.poll()); System.out.println(q.poll()); System.out.println(q.poll()); System.out.println(q.poll()); }}
执行结果
最后
感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!