最新要闻
- 为什么打不开空间_腾讯官方的解决方法
- 《终结者》T-1000成真!科学家研制出可固液转变机器人 形态科幻
- 当前观点:或命名为“高山” 魏牌全新插混MPV申报:红旗HQ9有话要说
- 印度版大G来啦!4排10座轴距超3米 马力只有90匹
- 坚持元宇宙不动摇:Meta百万美元年薪招聘VR程序员
- 环球观热点:女子下班回工作消息获赔加班费引热议!调查称仅1成多人拒绝下班秒回工作
- 全球即时:卢拉发推预告:“我将启程前往中国”,期望加强巴中贸易伙伴关系
- 能打比亚迪宋PLUS DM-i 哈弗枭龙MAX开订:用上Hi4电四驱
- 焦点关注:两大巨头“世纪大和解”!腾讯视频官方入驻抖音:昵称“鹅家”
- 天天日报丨13代标压高能轻薄本!华硕无畏15i 2023到手5699元:OLED好屏值得拥有
- 又来一份10年协议!微软与英国EE达成云游戏合作
- 焦点播报:《圣斗士星矢》真人版战斗预告:变身画面超燃!
- 温彬等:食品、能源价格双双下探,促内需政策仍须发力
- 快消息!7000mAh超大电池比肩充电宝!华为畅享60X官宣:实用体验才是王道
- 世界快资讯:女子看电视惊现3000多秒超长广告 直呼太离谱
- 环球今亮点!国内最新快递服务满意度出炉:顺丰、京东、邮政排前三 你经常用哪家?
广告
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
ThreadPoolExecutor源码学习
(资料图片仅供参考)
线程池ThreadPoolExecutor
ThreadPoolExecutor 继承结构
继承结构如图所示:ThreadPoolExecutor <- AbstractExecutorService <- ExecutorService <- Executor
public class ThreadPoolExecutor extends AbstractExecutorService { //...}/** * 实现了部分 ExecutorService 方法 * 1. submit 方法 * 2. invokeAny 方法 * 3. invokeAll 方法 */public abstract class AbstractExecutorService implements ExecutorService { /** * Callable -> FutureTask * FutureTask implements RunnableFuture * RunnableFuture extends Future, Runnable * * FutureTask Status: * NEW(0): 初始状态, 任务刚被创建或者正在计算中 * COMPLETING(1): 中间状态, 任务计算完成正在对结果进行赋值,或者正在处理异常 * NORMAL(2): 终止状态, 任务计算完成, 结果已经完成赋值 * EXCEPTIONAL(3): 终止状态, 任务计算过程发生异常无法处理,线程中断 * CANCELLED(4): 终止状态, 任务计算过程被取消 * INTERRUPTING(5): 中间状态, 任务计算过程已开始并被中断,正在修改状态 * INTERRUPTED(6): 终止状态,任务计算过程已开始并被中断,且已经完全停止 */ protected RunnableFuture newTaskFor(Callable callable) { return new FutureTask(callable); } protected RunnableFuture newTaskFor(Runnable runnable, T value) { return new FutureTask(runnable, value); } // 提交 callable 任务 public Future submit(Callable task) { if (task == null) throw new NullPointerException(); RunnableFuture ftask = newTaskFor(task); execute(ftask); return ftask; } // 提交 runnable 任务,返回 null public Future> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture ftask = newTaskFor(task, null); execute(ftask); return ftask; } // 提交 runnable 任务,返回 result public Future submit(Runnable task, T result) { if (task == null) throw new NullPointerException(); RunnableFuture ftask = newTaskFor(task, result); execute(ftask); return ftask; } // invokeAll // 为每一个任务创建对应的FutureTask, 并调用 execute 方法执行 // execute() 方法在 ThreadPoolExecutor 被实现 public List> invokeAll(Collection extends Callable> tasks) throws InterruptedException { if (tasks == null) throw new NullPointerException(); ArrayList> futures = new ArrayList>(tasks.size()); boolean done = false; try { for (Callable t : tasks) { RunnableFuture f = newTaskFor(t); futures.add(f); execute(f); } for (int i = 0, size = futures.size(); i < size; i++) { Future f = futures.get(i); // 如何任务此时还未执行完成,则阻塞获取对应的值 if (!f.isDone()) { try { f.get(); } catch (CancellationException ignore) { } catch (ExecutionException ignore) { } } } done = true; return futures; } finally { // 执行过程抛出无法处理的异常 if (!done) for (int i = 0, size = futures.size(); i < size; i++) // 取消任务的执行,如果任务已经执行完成,则不受影响 futures.get(i).cancel(true); } } // InvokeAny 方法逻辑待后续更新}/** * 在 Executor 的基础上定义了一系列任务执行和线程池管理方法 * * 1. submit: 提供方法执行带有返回值的任务 * 2. invokeAll: 提供方法执行指定的任务集合中的所有任务, 返回 List> * 3. invokeAny: 提供方法执行指定的任务集合中的所有任务, 将第一个执行完成的任务的结果作为返回值, 并终止其他线程的执行 * 4. isShutDown/isTerminated: 判断线程池状态方法 * 5. shutdown: 不再接受新的任务, 待所有任务执行完毕后关闭线程池 * 6. shutdownNow: 不再接受新的任务,直接关闭线程池 */public interface ExecutorService extends Executor { // ...}/** * 只定义了一个 execute 方法, 执行 Runnable 任务 */public interface Executor { void execute(Runnable command);}
ThreadPoolExecutor 关键参数及核心方法
关键参数
线程池状态参数
public class ThreadPoolExecutor extends AbstractExecutorService { // 线程池状态,由两部分构造 runState | workerCount // runState: 占2bit(29~30位) // workerCount: 占29bit(0~28位) // 符号位: 占1bit(最高位) private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // workerCount 最大容量: 2^29 - 1 private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1; /** * 线程池状态 * RUNNING: 运行状态,接受新任务,处理阻塞队列中的任务 * SHUTDOWN: 关闭状态,拒绝新任务,处理阻塞队列中的任务 * STOP: 停止状态,拒绝新任务,并中断当前正在执行的任务,不处理阻塞队列中的任务直接关闭 * TIDYING: 过度状态,当前线程池中的活动线程数降为0时的状态 * TERMINATED: 销毁状态,线程池彻底终止 */ private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;}
线程池状态转移图如下所示
- RUNNING: 线程池创建后进入的状态
- SHUTDOWN: 调用
shutdown
方法进入该状态,该方法主要包含如下操作- 更新线程池状态为
SHUTDOWN
- 中断空闲线程
interruptIdleWorkers()
- 所以已经存在任务队列中的任务还是能被正常执行完成
- 执行完所有任务后,先清除所有的worker,然后调用
tryTerminate()
,进入TIDYING
状态
- 更新线程池状态为
- STOP: 调用
shutdownNow()
方法进入该状态,该方法主要包含如下操作- 更新线程池状态为
STOP
- 中断所有线程
interruptWorkers()
- 清空任务队列
drainQueue()
- 立即调用
tryTerminate()
进入TIDYING
状态
- 更新线程池状态为
- TIDYING: 调用
terminated()
方法 - TERMINATED: 执行完
terminated()
方法进入该状态- ctl.set(ctlOf(TERMINATED, 0))
线程池管理参数
public class ThreadPoolExecutor extends AbstractExecutorService { // 任务队列 private final BlockingQueue workQueue; // 工作线程集合 private final HashSet workers = new HashSet(); // 线程池到达过的最大线程数量 private int largestPoolSize; // 已完成任务数 private long completedTaskCount; // 线程工厂,用于创建线程 private volatile ThreadFactory threadFactory; // 拒绝策略处理类 private volatile RejectedExecutionHandler handler; // 线程池中线程数量 > corePoolSize 情况下,空闲线程的最大存活时间 private volatile long keepAliveTime; // true: 线程数量 <= corePoolSize 情况下,空闲线程的最大存活时间也设置为 keepAliveTime // false(default): 线程数量 <= corePoolSize 情况下,空闲线程可以一直存活 private volatile boolean allowCoreThreadTimeOut; // 设置线程池 —— 核心线程数 private volatile int corePoolSize; // 设置线程池 —— 最大线程数 private volatile int maximumPoolSize; // 默认任务拒绝策略: 抛出异常 private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();}
核心方法
构造函数
// corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue 必须手动设置// threadFactory, handler 可以使用默认设置public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler;}
execute() 方法
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); // workerCount < corePoolSize,则直接添加一个 worker 执行该任务 if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } // workerCount >= corePoolSize, 则先尝试将任务添加到 workQueue if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); // 任务添加到 workQueue 后,执行recheck // 如果线程池未处于 Running 状态,则将刚刚添加的任务从阻塞队列中删除 if (!isRunning(recheck) && remove(command)) reject(command); // 如果线程池处于 Running 状态,则判断是否需要添加一个新的 worker else if (workerCountOf(recheck) == 0) addWorker(null, false); } // workerCount >= corePoolSize, 并且任务队列已满,添加失败 // 则尝试增加一个新的 worker 执行该任务 // 如果添加失败,则调用拒绝策略处理类 else if (!addWorker(command, false)) reject(command);}
execute
提交新任务的处理策略总结如下:
workerCount < corePoolSize
: 直接添加一个新的 worker 执行任务workerCount >= corePoolSize
: 尝试添加到任务队列- 添加成功则执行
recheck
; - 添加失败则尝试创建一个新的 worker 来执行该任务,创建worker失败则调用拒绝策略处理
- 添加成功则执行
addWorker() 方法
该方法用于添加一个新的 Worker 到线程池中,包括两个参数:
- firstTask(Runnable): 创建完成后第一个执行的任务
- core(boolean):
- true: 使用 corePoolSize 为最大线程数量
- false: 使用 maxPoolSize 为最大线程数量
private boolean addWorker(Runnable firstTask, boolean core) { // 循环标签,方便跳出 retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); /** * 判断线程池状态:以下状态才能添加 worker * 1. 线程池处于 RUNNING 状态 * 2. 线程池处于 SHUTDOWN 状态 且 firstTask 为 null 且 workQueue 不为空 */ if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false; for (;;) { int wc = workerCountOf(c); // 判断当前 worker 数量是否还能继续添加 if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false; // CAS 更新 workerCount if (compareAndIncrementWorkerCount(c)) break retry; // CAS 更新失败则自旋重试 c = ctl.get(); if (runStateOf(c) != rs) continue retry; } } // worker 启动标识 boolean workerStarted = false; // worker 加入 HashSet 集合标识 boolean workerAdded = false; Worker w = null; try { // Worker构造方法调用 threadFactory 创建新的线程 w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; // 加锁,保证多个线程同时添加 worker 到集合中的安全性 mainLock.lock(); try { int rs = runStateOf(ctl.get()); // if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // 判断该线程是否已经启动 throw new IllegalThreadStateException(); workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } if (workerAdded) { t.start(); // 启动线程 workerStarted = true; } } } finally { if (! workerStarted) // worker 启动失败,则做一些回退处理 // 从 workers 集合中删除 worker // workCount 减少1 addWorkerFailed(w); } return workerStarted;}
Worker
Worker
类实现了Runnable
接口,所以在创建线程中可以传入自己作为任务,然后线程启动时调用自己的run()
方法
Worker
类继承自AQS,所以其本身也是一把锁(不可重入锁),在执行任务时通过lock()
锁住自己,保证worker正在执行时不会去获取其他任务来执行
private final class Worker extends AbstractQueuedSynchronizer implements Runnable { Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; // 传入自己作为 Runnable 实例 // 线程启动时执行 Worker.run() 方法 this.thread = getThreadFactory().newThread(this); } // run() 则调用外部 ThreadPoolExecutor 的 runWorker 方法 public void run() { runWorker(this); }}
runWorker() 方法
final void runWorker(Worker w) { Thread wt = Thread.currentThread(); // 初始任务 Runnable task = w.firstTask; // firstTask 执行过一次后被置为 null w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { // 循环获取任务执行,复用已有线程 // getTask() 从任务队列获取task while (task != null || (task = getTask()) != null) { w.lock(); // 若线程池处于 STOP 状态,但线程没有中断执行,则调用 interrupt() 方法完成中断 if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { // 钩子方法,任务执行前逻辑 // 默认实现为空,可自定义线程池扩展该功能 beforeExecute(wt, task); Throwable thrown = null; try { // 执行任务 task.run(); } catch (RuntimeException x) { thrown = x; throw x; } catch (Error x) { thrown = x; throw x; } catch (Throwable x) { thrown = x; throw new Error(x); } finally { // 钩子方法,任务执行后逻辑 // 默认实现为空,可自定义线程池扩展该功能 afterExecute(task, thrown); } } finally { task = null; w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { // 删除 worker,线程执行完毕 processWorkerExit(w, completedAbruptly); }}
getTask() 方法
从
workQueue
中获取任务,返回 Runnable 任务或者 null
return Runnable
: worker正常执行return null
: 获取不到任务,进入 processWorkerExit 结束当前 worker
private Runnable getTask() { boolean timedOut = false; // Did the last poll() time out? for (;;) { int c = ctl.get(); int rs = runStateOf(c); /** * 判断是否回收当前线程: * 情况1. 线程池状态为 SHUTDOWN && workQueue 为空 * 情况2. 线程池状态为 STOP || TERMINATED */ if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { decrementWorkerCount(); return null; } int wc = workerCountOf(c); // true: poll()获取任务,阻塞获取,设置超时时间 // false: take()获取任务,阻塞获取 boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; /** * 判断是否回收当前线程: * 条件1. workerCount > maxPoolSize 或 当前线程获取任务超时 * 条件2. workerCount > 1 或 workQueue 为空 * * 同时满足条件1和条件2,则CAS减少workerCount,并返回null */ if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) { if (compareAndDecrementWorkerCount(c)) return null; continue; } // 不满足回收当前线程的条件,则执行后续获取任务的逻辑 try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } }}
processWorkerExit() 方法
从 workers 工作线程集合中删除当前 worker,回收线程。
private void processWorkerExit(Worker w, boolean completedAbruptly) { // 如果是异常退出,则需要手动完成 workerCount 的更新 if (completedAbruptly) decrementWorkerCount(); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { completedTaskCount += w.completedTasks; workers.remove(w); } finally { mainLock.unlock(); } // 尝试终止线程池 tryTerminate(); int c = ctl.get(); if (runStateLessThan(c, STOP)) { if (!completedAbruptly) { int min = allowCoreThreadTimeOut ? 0 : corePoolSize; if (min == 0 && ! workQueue.isEmpty()) min = 1; if (workerCountOf(c) >= min) return; // replacement not needed } // 1.如果是异常退出则直接添加一个新的 worker // 2.如果 workerCount < 最小线程数要求,则添加一个新的 worker addWorker(null, false); }}
总结
创建线程池提交任务,整体执行流程如下图所示:
- execute(): 提交 Runnable Task
- submit(): 提交 Callable Task
- wc: workerCount, 线程数量
- rs: runState, 线程池运行状态
- reject: 执行任务拒绝策略
关键词:
-
ThreadPoolExecutor源码学习
线程池ThreadPoolExecutorThreadPoolExecutor继承结构继承结构如图所示:ThreadPoolExecutor<-AbstractExecutorServ
来源: 全球快讯:从spring boot泄露到接管云服务器平台
ThreadPoolExecutor源码学习
图文介绍 Windows 系统下打包上传 IOS APP 流程
【Visual Leak Detector】使用注意事项
一个TCP 连接可以发送多少个HTTP请求?
为什么打不开空间_腾讯官方的解决方法
《终结者》T-1000成真!科学家研制出可固液转变机器人 形态科幻
当前观点:或命名为“高山” 魏牌全新插混MPV申报:红旗HQ9有话要说
印度版大G来啦!4排10座轴距超3米 马力只有90匹
坚持元宇宙不动摇:Meta百万美元年薪招聘VR程序员
环球观热点:女子下班回工作消息获赔加班费引热议!调查称仅1成多人拒绝下班秒回工作
全球即时:卢拉发推预告:“我将启程前往中国”,期望加强巴中贸易伙伴关系
世界简讯:【一行代码秒上云】Serverless六步构建全栈网站
科创人·中建三局一公司尹奎:数字化变革能创造全新行业,其意义超越形式、范式创新
当前关注:CAD二次开发,安装程序中写注册表
滚动:低代码开发,是稳扎稳打还是饮鸩止渴?
快报:【金融街发布】人民银行:3月货币供应量M2同比增长12.7% 比上月回落0.2个百分点
能打比亚迪宋PLUS DM-i 哈弗枭龙MAX开订:用上Hi4电四驱
焦点关注:两大巨头“世纪大和解”!腾讯视频官方入驻抖音:昵称“鹅家”
天天日报丨13代标压高能轻薄本!华硕无畏15i 2023到手5699元:OLED好屏值得拥有
又来一份10年协议!微软与英国EE达成云游戏合作
焦点播报:《圣斗士星矢》真人版战斗预告:变身画面超燃!
温彬等:食品、能源价格双双下探,促内需政策仍须发力
精彩看点:【业务自动化平台】上海道宁与UiPath致力于让每个企业、每个人都能充分利用自动化带来的成就和优势
微服务保护--Sentinel
ASP.NET Post, FromBody 接参总是null 空值. Web api 前端传递是有值的,怎么回事?
【新华500】新华500指数(989001)11日微跌0.07%
快消息!7000mAh超大电池比肩充电宝!华为畅享60X官宣:实用体验才是王道
世界快资讯:女子看电视惊现3000多秒超长广告 直呼太离谱
环球今亮点!国内最新快递服务满意度出炉:顺丰、京东、邮政排前三 你经常用哪家?
简讯:大家不看电视了?海信:电视开机率低是个伪命题
环球快讯:别YY失控!深圳一辆特斯拉钣喷中心破窗而出 差点掉下来:官方回应
热议:希腊神话的英语典故
重试,让程序更健壮
aix系统如何查看网卡配置
模型训练与推理中为什么需要使用GPU?基本概念梳理
全球球精选!2023年最新iOS打包发布流程汇总
韩总统府称网传美监听韩政府文件部分系伪造
多地现沙尘暴!中央气象台首席预报员:沙尘天气无需根治
英特尔锐炫A750最新驱动游戏实测:进步巨大
刷新认知!男子站临海近乎垂直石壁上钓鱼:网友直呼请勿模仿
环球新动态:世界首个“九尾狐甲鱼”化石被发现:长相奇特怪异
全球第一批25个GPT模型开始自由生活
当前资讯!应用火山引擎 DataTester“避坑”,抖音实现用 A/B 实验快速试错
路由跳转及传参
每日消息!堆叠面积图的优点和缺点有哪些?
跟ChatGPT聊天、需求润色优化,禅道OpenAI 插件发布!
三星9082怎么恢复出厂设置?三星9082手机参数
索尼w570现在值多少钱?索尼w570参数
台式机怎么设置无线上网?台式机怎么调节屏幕亮度?
巧克力键盘是什么意思?巧克力键盘和机械键盘的区别是什么?
诺基亚n82上市价格是多少?诺基亚n82手机参数
每日时讯!鑫顺看市:4.11黄金守住1980关键位,多头或再次卷土重来
当前资讯![网络]应用层协议:HTTP / HTTPS
用ChatGPT问.NET的相关问题,.NET工程师的前景不错
每日热讯!男子被鱼刺卡喉硬吞饭团:结果扎穿食管
天天速看:力压宝马X5 理想L7交付首月狂卖8009台:稳居国内中大型SUV销量第一
世界热门:米其林中国回应顾客用餐后上吐下泻:非常重视消费者健康安全
焦点!紫光展锐首款车规级5G座舱芯片平台A7870公布:6nm加持、NPU算力媲美骁龙8155
全球热推荐:蓝牌要成历史?新款奔腾T90官图:全新车牌引遐想
世界新消息丨又萌又飒!池州一高校女生穿公主裙一“跑”走红
在寻找 LastPass 的更好替代品吗?
当前简讯:金融系统NTP时钟同步(网络校时服务器)架设工作详情
[网络]TCP的三次握手与四次挥手[转载]
每日焦点!Python程序笔记20230301
云图说|图解云消息服务KooMessage
环球微资讯!充电仅需18秒!中科大研发出新型水系锌离子电池
或为问界M9 赛力斯大型SUV专利图曝光:有点“震撼”
天天头条:车评人表扬华为问界:看不见的底盘件 大面积用铝合金材料
环球信息:林州“网红试胆石”出现裂缝仍有游客打卡 官方回应
天天速讯:299元 小米小爱音箱儿童版开卖:童声专项识别优化
世界银行上调2023年全球经济增长预期至2%
关于算法开源乱七八糟事
【报资讯】RDIF.vNext全新低代码快速开发框架平台发布
环球聚焦:基于pdfbox实现的pdf添加文字水印工具
【全球新要闻】老爸老妈浪漫史第五季(老爸老妈的浪漫史第五季结局是什么?)
爷青回!《灌篮高手》中国首映礼官宣:4月15日见
世界信息:快科技App 5.2.1新版发布:新增沉浸式阅读、排行榜一键分享长图
环球通讯!特斯拉下代电机不用稀土 国内专家:屁股决定脑袋 马斯克是迫不得已
今日聚焦!"全聚德连亏三年"登热搜:今年净亏损2.78亿元
时讯:iPhone 15 Pro相机凸起3.78毫米:约2枚1元硬币厚度
通讯!GGII:2022年中国锂电池回收处理废旧锂电池量41万吨,同比增37%
环球速讯:如何用Golang处理每分钟100万个请求
天天热点评!全网最详细中英文ChatGPT-GPT-4示例文档-步骤指示智能生成从0到1快速入门——官网推荐的48种最佳应用场景(附python/node.js
【高端访谈】“与时俱进”|绿债担保品管理驱动绿色金融体系建设升级——专访中央结算公司担保品业务负责人
每日看点!电动牙刷别乱买 买错代价太大了
全球即时:小鹏P7迎整车OTA:6项新增功能 360全景影像正式上线
世界热消息:挑战不可能!阿维塔11在“8D山城”重庆开启城区NCA智驾导航辅助体验
汽车促销潮蔓延 车险会降价吗?业内人士:没有直接影响
环球时讯:成都双流现飞机“横穿马路” 网友:真“飞”机动车道
钦州白癜风专科医院哪个好-白癜风患者如何缓解压力
通过Nginx定义Header头信息
全国18省份都有扬沙浮尘天气!沙尘暴趁夜入京:口罩挡不住行人吃土
今日要闻!乘联会:汽车价格没崩盘 降价潮不存在
天天简讯:别回家充电!电动车爆炸致死楼上邻居 全国又有多起发生:实测起火后可怕
热推荐:中科大研发镧系新型固态电解质 全固态锂金属电池新突破
每日消息!聚焦京津冀协同发展|培育农业品牌 让河北新鲜蔬菜装进北京“菜篮子”
【读财报】两年持有期基金回撤透视:广发、上投摩根基金等产品亏损幅度居前
四大证券报精华摘要:4月11日
机械鼠标看了心动?智商税别再交了!