首页 文章 精选 留言 我的

精选列表

搜索[云真机矩阵],共10006篇文章
优秀的个人博客,低调大师

这事给整成了

通常情况下,macOS 仅支持苹果自有硬件。但在 IT 运维中,有时需要针对特定场景测试 macOS——例如开发 Xcode 应用、适配苹果生态产品(如 iPhone/iPad 应用),或进行安全研究。若为团队成员每人配备一台苹果设备,成本高且效率低。而“黑苹果”(即在非苹果硬件上运行 macOS)借助虚拟化技术,可让用户在现有服务器或电脑上运行 macOS,大幅降低硬件投入。典型应用场景包括:

优秀的个人博客,低调大师

Llama 4 不是开源,比 DeepSeek 格局差多了

Meta昨天悄默声的发了Llama 4系列AI模型,CEO马克·扎克伯格在宣传视频中反复强调这将"加速开源AI发展"并让"全世界受益"。 不过,这一宣传却在AI开发社区引发了激烈争议。油管知名博主1littlecoder频道就做了一支很辛辣的视频(Llama 4 is NOT Open Source!),对Meta的开源主张提出了强烈质疑,指出Llama 4的许可条款与真正的开源精神相去甚远。 一、Meta的Llama 4发布与开源宣言 马克·扎克伯格在Llama 4发布视频中充满热情地宣布:"今天是Llama 4的日子。我们的目标是构建世界领先的AI,将其开源,并使其普遍可访问,让全世界都能受益。我一直认为开源AI将成为领先模型,而随着Llama 4,这开始变为现实。" 扎克伯格的宣言表明Meta正全力押注开源AI战略,试图在与OpenAI、Google等闭源模型巨头的竞争中,通过开源路线赢得主导地位。Meta在官方发布中反复强调Llama 4的"开源"性质,将其视为企业AI战略的核心优势。 然而,这一"开源"的定义很快受到了社区的严格审视。1littlecoder直言不讳地表示:"这是对开源的污蔑,与开源毫无关系。在这个视频中,我将论证为什么我们应该停止称Llama 4为开源模型。你可以称它为开放模型,你可以称它为开放权重模型,但它不是开源的。" 二、开源的本质与Llama 4的下载壁垒 开源软件的基本原则之一是普遍可访问性。正如视频中所述:"开源通过开源或免费许可促进对产品的普遍访问。这意味着任何人都应该能够访问你的产品,而不会有太多麻烦。" 与其他真正开源的AI模型相比,Llama 4的获取过程显得异常复杂。1littlecoder指出,即使是中国公司的模型如DeepSeek和Qwen,用户只需点击几下即可下载。而Meta的模型却设置了多重障碍: "Meta的模型要求你首先登录Hugging Face账户,这点我能理解,他们可能有垃圾邮件问题。然后填写表格,务必提供你的法定全名。我是说,为什么下载PyTorch权重或一些随机二进制文件需要提供我的法定姓名?还有出生日期、完整的组织名称、所有公司标识符。" 更令人担忧的是,表格上明确警告:"避免使用首字母缩写和特殊字符。未能按照这些指示操作可能会阻止你访问此模型和Hugging Face上的其他模型。提交后,你将无法编辑此表格。因此,请确保所有信息准确无误。" 这意味着一旦因填写信息不当被Meta禁止,用户可能永远无法从Hugging Face下载该模型,这与开源软件的普遍可访问性原则直接冲突。 三、Llama 4的许可证限制与开源定义的冲突 更具争议性的是Llama 4的社区许可协议,1littlecoder将其描述为"对开源的污蔑"。这份许可协议包含多项限制,直接挑战了传统开源定义: 首先是用户限制条款:"如果你拥有一家月活跃用户超过7亿的公司,你不能使用这个模型。"虽然这对大多数开发者来说影响有限,但它违背了开源软件不应对使用者有歧视的基本原则。 "如果你来自Google或者像OpenAI这样的组织,你不能使用这个模型。对我们这些可怜的家伙来说,我们可以使用这个模型。"创作者半开玩笑地指出。 其次是关于再分发的严格要求。许可证规定,如果分发或提供Llama材料,必须显示"使用Llama构建"的标志。1littlecoder对此表示强烈不满:"为什么我要这样做?你想加速开源,对吧?你不是在寻求任何好处,因为你相信开源。只要给我模型,我想怎么用就怎么用。这是愚蠢,完全的愚蠢。" 更令人震惊的是命名要求:"如果你使用Llama材料或任何Llama材料的输出或结果来创建、训练、微调或以其他方式改进分发或提供的AI模型,你还应该在任何此类AI模型名称的开头包含'Llama'。" "例如,如果你采用Qwen并用Llama相关模型进行某种微调,那么你必须称之为Llama Qwen、Llama Deep Seek或Llama GPT-4。"创作者解释道,"一个是标明'使用Llama构建',第二个是你必须在名称前加前缀,比如你必须说Llama然后是其他模型。我不认为这是开源。" 此外,还有版权声明要求:"在你分发的Llama材料的所有副本中,你必须包含以下归属声明,并与分发的此类副本一起提供声明文本文件:'Llama 4的许可证和Llama 4社区许可证,版权Meta平台,保留所有权利。'" 四、AI社区对Llama 4许可的专业评估 为验证自己的观点,1littlecoder向Google的Gemini AI提出了问题:"这是开源吗?它符合开源许可吗?" Gemini的回答证实了创作者的疑虑:"这个许可证不完全符合基于普遍接受的开源定义和原则的开源许可证。" Gemini列出了多个原因: 商业限制(对大型平台的使用限制) "使用Llama构建"的强制标注要求 添加"Llama"前缀的命名要求 附加声明的要求 Gemini进一步解释了为什么这些问题对开源重要:"像OSI(开源倡议组织)批准的开源许可遵循这些原则:使用自由、学习自由、再分发自由、修改自由,没有歧视。" 1littlecoder对此感到无比沮丧:"天哪,你甚至不能下载这个模型,如果你因为提供了一些错误的详细信息而被Meta封禁一次,那么你就再也无法从Hugging Face下载这个模型了。这是多么愚蠢!" 五、Llama 4的技术规格与模型系列 尽管存在许可争议,Llama 4在技术方面仍展现出令人印象深刻的能力。Meta发布了两个初始模型,并预告了两个即将推出的模型: 1. Llama 4 Scout 极快速度,原生多模态 业界领先的近乎无限的1000万token上下文长度 设计为在单个GPU上运行 170亿参数×16专家 "同类中性能最高的小型模型" 2. Llama 4 Maverick 据称在所有基准测试中击败GPT-4.0和Gemini Flash 2 比DeepSeek v3更小更高效,但在文本方面仍有可比性 原生多模态 170亿参数×128专家 设计为在单个主机上运行,便于推理 扎克伯格称其为"一头野兽" 即将推出的模型: Llama 4 Reasoning - 预计在下个月有更多消息 Llama 4 Behemoth - 扎克伯格描述为"巨大",超过2万亿参数,"我不知道有人在训练更大的模型",据称已经是"世界上性能最高的基础模型",而且"甚至还没有完成训练" 扎克伯格对Llama 4系列的愿景是雄心勃勃的:"总体而言,Llama 4是Meta AI和开源的一个里程碑。首次,最好的小型、中型,可能很快是前沿模型将是开源的。还有很多工作要做,但这里的轨迹很明确。" 六、对AI开源未来的思考与挑战 1littlecoder在结束时呼吁AI社区重新思考什么才是真正的开源:"请不要称这为开源。我相信,将任何进入Hugging Face的愚蠢模型称为开源,对于开源代表的内容或开源支持者来说,是一种污蔑。这不是开源,只是你可以下载并带有一堆限制的开放权重。" 转载自https://weibo.com/1233486457/Pm1mhEIkH

优秀的个人博客,低调大师

这次绝对让你轻松学习线程池

在这里插入图片描述 5分钟了解线程池 老王 是个深耕在帝都的一线码农,辛苦一年挣了点钱,想把钱存储到银行卡里,钱银行卡办理遇到了如下的遭遇 老王 银行门口取号后发现有柜台营业但是没人办理业务 直接办理了。 老王 取号后发现柜台都有人在办理,等待席有空地,去 坐着等办理去了。 老王 取号后发现柜台都有人办理,等待席也人坐满了,这个时候银行经理看到小麦是老实人本着关爱老实人的态度,新开一个 临时窗口给他办理了。 老王 取号后发现柜台都满了,等待座位席也满了, 临时窗口也人满了。这个时候银行经理给出了若干 解决策略。 直接告知人太多不给你办理了。 看到 老王 就来气,也不给不办理也不让他走。 经理让 老王 取尝试跟座位席中最前面的人聊一聊看是否可以加塞,可以就办理,不可以还是被踢走。 经理直接跟 老王 说谁让你来的你找谁去我这办理不了。 上面的这个流程几乎就跟JDK线程池的大致流程类似, 营业中的3个窗口对应核心线程池数:corePoolSize 银行总的营业窗口数对应:maximumPoolSize 打开的临时窗口在多少时间内无人办理则关闭对应:unit 银行里的等待座椅就是等待队列:workQueue 无法办理的时候银行给出的解决方法对应:RejectedExecutionHandler threadFactory 该参数在JDK中是 线程工厂,用来创建线程对象,一般不会动。 5分钟线程池的核心工作流程讲解完毕,更细节的知识看下面。 什么是线程池 简单理解就是 预先创建好一定数量的线程对象,存入缓冲池中,需要用的时候直接从缓冲池中取出,用完之后不要销毁,还回到缓冲池中。 线程池存在必要性 提高线程的利用率,降低资源的消耗。 提高响应速度,线程的创建时间为T1,执行时间T2,销毁时间T3,用线程池可以免去T1和T3的时间。 便于统一管理线程对象 可控制最大并发数 手动实现 如果先不看线程池源码让我们自己手动实现一个线程池你可以考虑到几个重要点? 有若干个初始化好的线程数组来充当线程池。 线程池要去一个 等待的任务队列 中去拿任务。 简单来说就是初始化N个线程充当线程池然后一起去阻塞队列中进行阻塞take,新添加的任务都通过put将任务追加到任务队列,关于任务队列的讲解看这blog 核心类 publicclassMyThreadPool2{//线程池中默认线程的个数为5privatestaticintWORK_NUM=5;//队列默认任务个数为100来不及保存任务privatestaticintTASK_COUNT=100;//工作线程组privateWorkThread[]workThreads;//任务队列,作为一个缓冲privatefinalBlockingQueue<Runnable>taskQueue;//用户在构造这个池,希望的启动的线程数privatefinalintworker_num;//创建具有默认线程个数的线程池publicMyThreadPool2(){this(WORK_NUM,TASK_COUNT);}//创建线程池,worker_num为线程池中工作线程的个数publicMyThreadPool2(intworker_num,inttaskCount){if(worker_num<=0)worker_num=WORK_NUM;if(taskCount<=0)taskCount=TASK_COUNT;this.worker_num=worker_num;taskQueue=newArrayBlockingQueue<>(taskCount);workThreads=newWorkThread[worker_num];for(inti=0;i<worker_num;i++){workThreads[i]=newWorkThread();workThreads[i].start();}Runtime.getRuntime().availableProcessors();}//执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器决定publicvoidexecute(Runnabletask){try{taskQueue.put(task);//阻塞放置任务}catch(InterruptedExceptione){e.printStackTrace();}}//销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁publicvoiddestroy(){//工作线程停止工作,且置为nullSystem.out.println("准备关闭线程池");for(inti=0;i<worker_num;i++){workThreads[i].stopWorker();workThreads[i]=null;//helpgc}taskQueue.clear();//清空任务队列}//覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数@OverridepublicStringtoString(){return"线程池大小:"+worker_num+"等待执行任务个数:"+taskQueue.size();}//内部类,工作线程privateclassWorkThreadextendsThread{@Overridepublicvoidrun(){Runnabler=null;try{while(!isInterrupted()){r=taskQueue.take();//阻塞获得任务if(r!=null){System.out.println(getId()+"准备执行:"+r);r.run();}r=null;//helpgc;}}catch(Exceptione){//TODO:handleexception}}publicvoidstopWorker(){interrupt();}}} 测试类 publicclassTestMyThreadPool{publicstaticvoidmain(String[]args)throwsInterruptedException{//创建3个线程的线程池MyThreadPool2t=newMyThreadPool2(3,5);t.execute(newMyTask("testA"));t.execute(newMyTask("testB"));t.execute(newMyTask("testC"));t.execute(newMyTask("testD"));t.execute(newMyTask("testE"));System.out.println(t);Thread.sleep(10000);t.destroy();//所有线程都执行完成才destorySystem.out.println(t);}//任务类staticclassMyTaskimplementsRunnable{privateStringname;privateRandomr=newRandom();publicMyTask(Stringname){this.name=name;}publicStringgetName(){returnname;}@Overridepublicvoidrun(){//执行任务try{Thread.sleep(r.nextInt(1000)+2000);//随机休眠}catch(InterruptedExceptione){System.out.println(Thread.currentThread().getId()+"被打断:"+Thread.currentThread().isInterrupted());}System.out.println("任务"+name+"完成");}}} ThreadPoolExecutor ThreadPoolExecutor是JDK中所有线程池实现类的父类,构造函数有多个入参通过灵活的组合来实现线程池的初始化,核心构造函数如下。 publicThreadPoolExecutor(intcorePoolSize,intmaximumPoolSize,longkeepAliveTime,TimeUnitunit,BlockingQueue<Runnable>workQueue,ThreadFactorythreadFactory,RejectedExecutionHandlerhandler) 重要参数解析 corePoolSize 此值是用来初始化线程池中核心线程数,当线程池中线程池数< corePoolSize时,系统默认是添加一个任务才创建一个线程池。可以通过调用prestartAllCoreThreads方法一次性的启动corePoolSize个数的线程。当线程数 = corePoolSize时,新任务会追加到workQueue中。 maximumPoolSize maximumPoolSize表示允许的最大线程数 = (非核心线程数+核心线程数),当BlockingQueue也满了,但线程池中总线程数 < maximumPoolSize时候就会再次创建新的线程。 keepAliveTime 非核心线程 =(maximumPoolSize - corePoolSize ) ,非核心线程闲置下来不干活最多存活时间。 unit 线程池中非核心线程保持存活的时间 TimeUnit.DAYS; 天 TimeUnit.HOURS; 小时 TimeUnit.MINUTES; 分钟 TimeUnit.SECONDS; 秒 TimeUnit.MILLISECONDS; 毫秒 TimeUnit.MICROSECONDS; 微秒 TimeUnit.NANOSECONDS; 纳秒 workQueue 线程池 等待队列,维护着等待执行的Runnable对象。当运行当线程数= corePoolSize时,新的任务会被添加到workQueue中,如果workQueue也满了则尝试用非核心线程执行任务,另外等待队列尽量用有界的哦!! threadFactory 创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等。 handler corePoolSize、workQueue、maximumPoolSize都不可用的时候执行的 饱和策略。 AbortPolicy :直接抛出异常,默认用此 CallerRunsPolicy:用调用者所在的线程来执行任务 DiscardOldestPolicy:丢弃阻塞队列里最老的任务,队列里最靠前的任务 DiscardPolicy :当前任务直接丢弃 想实现自己的饱和策略,实现RejectedExecutionHandler接口即可 形象流程图如下: 提交 execute 不需要返回 //核心思想跟上面的流程图类似publicvoidexecute(Runnablecommand){if(command==null)//规范性检查thrownewNullPointerException();intc=ctl.get();//当前工作的线程数跟线程状态ctl=AtomicIntegerCAS级别if(workerCountOf(c)<corePoolSize){if(addWorker(command,true))//如果当前线程池中工作线程数小于核心线程数,直接添加任务然后returnreturn;c=ctl.get();//添加失败了重新获得线程池中工作线程数}if(isRunning(c)&&workQueue.offer(command)){//线程池状态是否处于可用,可用就尝试将线程添加到queueintrecheck=ctl.get();//获得线程池状态if(!isRunning(recheck)&&remove(command))reject(command);//如果线程状态不在运行中则remove该任务elseif(workerCountOf(recheck)==0)addWorker(null,false);}elseif(!addWorker(command,false))//尝试将任务用非核心线程执行,reject(command);//失败了则执行失败策略。} submit 需要返回值 ThreadPoolExecutor extends AbstractExecutorService父类中存在一个submit方法, public<T>Future<T>submit(Callable<T>task){if(task==null)thrownewNullPointerException();RunnableFuture<T>ftask=newTaskFor(task);execute(ftask);returnftask;} 关闭线程池 注意线程之间是协作式的哦,所以的关闭只是发出关闭指令。 shutdown() 将线程池状态置为shutdown,并不会立即停止: 停止接收外部submit的任务 内部正在跑的任务和队列里等待的任务,会执行完 等到第二步完成后,才真正停止 shutdownNow() 将线程池状态置为stop。企图立即停止,事实上不一定: 跟shutdown()一样,先停止接收外部提交的任务 忽略队列里等待的任务 尝试将正在跑的任务interrupt中断 返回未执行的任务列表 shutdown 跟shutdownnow简单来说区别如下: shutdownNow()能立即停止线程池,正在跑的和正在等待的任务都停下了。这样做立即生效,但是风险也比较大。shutdown()只是关闭了提交通道,用submit()是无效的;而内部该怎么跑还是怎么跑,跑完再停。 awaitTermination pool.showdown()booleanb=pool.awaitTermination(3,TimeUnit.SECONDS) awaitTermination有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。这个方法会使线程等待timeout时长,当超过timeout时间后,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用,调用后当前线程会阻塞,直到 等所有已提交的任务(包括正在跑的和队列中等待的)执行完 或者等超时时间到 或者线程被中断,抛出InterruptedException 总结 优雅的关闭,用shutdown() 想立马关闭,并得到未执行任务列表,用shutdownNow() 优雅的关闭,发出关闭指令后看下是否真的关闭了用awaitTermination()。 合理配置线程池 线程在Java中属于稀缺资源,线程池不是越大越好也不是越小越好。任务分为计算密集型、IO密集型、混合型。 计算密集型:大部分都在用CPU跟内存,加密,逻辑操作业务处理等。 IO密集型:数据库链接,网络通讯传输等。 计算密集型一般推荐线程池不要过大,一般是CPU数 + 1,+1是因为可能存在 页缺失(就是可能存在有些数据在硬盘中需要多来一个线程将数据读入内存)。如果线程池数太大,可能会频繁的 进行线程上下文切换跟任务调度。获得当前CPU核心数代码如下: Runtime.getRuntime().availableProcessors(); IO密集型:线程数适当大一点,机器的Cpu核心数*2。 混合型:如果密集型站大头则拆分的必要性不大,如果IO型占据不少有必要,Mark 下。 常见线程池 每个线程池都是一个实现了接口ExecutorService并且继承自ThreadPoolExecutor的具体实现类,这些类的创建统一由一个工厂类Executors来提供对外创建接口。Executors框架图如下: ThreadPoolExecutor中一个线程就是一个Worker对象,它与一个线程绑定,当Worker执行完毕就是线程执行完毕。而Worker带了锁AQS,根据我后面准备写的读写锁的例子,发现线程池是线程安全的。看看图二的类图。下面简单介绍几个常用的线程池模式。 FixedThreadPool 定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程。 使用的 无界的等待队列是 LinkedBlockingQueue。使用时候小心堵满等待队列。 SingleThreadPool 只有一条线程来执行任务,适用于有顺序的任务的应用场景,也是用的无界等待队列 CachedThreadPool 可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。任务队列用的是SynchronousQueue如果生产多快消费慢,则会导致创建很多线程需注意。 WorkStealingPool JDK7以后 基于ForkJoinPool实现。PS:其中FixedThreadPool、SingleThreadPool、CachedThreadPool都用的无界等待队列,因此实际工作中都不建议这样做的哦,阿里巴巴Java编程规范建议如下:最后来个简单的线程使用demo: publicclassUseThreadPool{//工作线程staticclassWorkerimplementsRunnable{privateStringtaskName;privateRandomr=newRandom();publicWorker(StringtaskName){this.taskName=taskName;}publicStringgetName(){returntaskName;}@Overridepublicvoidrun(){System.out.println(Thread.currentThread().getName()+"当前任务:"+taskName);try{TimeUnit.MILLISECONDS.sleep(r.nextInt(100)*5);}catch(Exceptione){e.printStackTrace();}}}staticclassCallWorkerimplementsCallable<String>{privateStringtaskName;privateRandomr=newRandom();publicCallWorker(StringtaskName){this.taskName=taskName;}publicStringgetName(){returntaskName;}@OverridepublicStringcall()throwsException{System.out.println(Thread.currentThread().getName()+"当前任务:"+taskName);returnThread.currentThread().getName()+":"+r.nextInt(100)*5;}}publicstaticvoidmain(String[]args)throwsInterruptedException,ExecutionException{ExecutorServicepool=newThreadPoolExecutor(2,4,3,TimeUnit.SECONDS,newArrayBlockingQueue<Runnable>(10),newThreadPoolExecutor.DiscardOldestPolicy());//ExecutorServicepool=Executors.newCachedThreadPool();for(inti=0;i<5;i++){Workerworker=newWorker("Runnable_"+i);pool.execute(worker);}for(inti=0;i<5;i++){CallWorkercallWorker=newCallWorker("CallWorker_"+i);Future<String>result=pool.submit(callWorker);System.out.println(result.get());}pool.shutdown();}} ScheduledThreadPoolExecutor 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。看构造函数:调用的还是ThreadPoolExecutor构造函数,区别不同点在于任务队列是用的DelayedWorkQueue,没什么新奇的了。 核心函数讲解: schedule 只执行一次,任务还可以延时执行,传入待执行任务跟延时时间。 scheduleAtFixedRate 提交固定时间间隔的任务,提交任务,延时时间,已经循环时间间隔时间。这个的含义是只是在固定的时间间隔尝试运行该任务。 scheduleWithFixedDelay 提交固定延时间隔执行的任务。上一个任务执行完毕后等多久再执行下个任务,这个中间时间叫 FixedDelay 其中 scheduleAtFixedRate 跟 scheduleWithFixedDelay区别如下图 scheduleAtFixedRate任务超时状态,比如我们设定60s执行一次,其中第一个任务时长 80s,第二个任务20s,第三个任务 50s。 第一个任务第0秒开始,第80s结束. 第二个任务第80s开始,在第100s结束. 第三个任务第120s秒开始,170s结束. 第四个任务从180s开始. 简单Mark个循环任务demo: classScheduleWorkerimplementsRunnable{publicfinalstaticintNormal=0;//普通任务类型publicfinalstaticintHasException=-1;//会抛出异常的任务类型publicfinalstaticintProcessException=1;//抛出异常但会捕捉的任务类型publicstaticSimpleDateFormatformater=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");privateinttaskType;publicScheduleWorker(inttaskType){this.taskType=taskType;}@Overridepublicvoidrun(){if(taskType==HasException){System.out.println(formater.format(newDate())+"异常产生");thrownewRuntimeException("有异常");}elseif(taskType==ProcessException){try{System.out.println(formater.format(newDate())+"异常产生被捕捉");thrownewRuntimeException("异常被捕捉");//异常导致下个任务无法执行}catch(Exceptione){System.out.println("异常被主播");}}else{System.out.println("正常"+formater.format(newDate()));}}}publicclassSchTest{publicstaticvoidmain(String[]args){ScheduledThreadPoolExecutorschedule=newScheduledThreadPoolExecutor(1);schedule.scheduleAtFixedRate(newScheduleWorker(ScheduleWorker.HasException),1000,3000,TimeUnit.MILLISECONDS);//任务在1秒后执行周期3秒schedule.scheduleAtFixedRate(newScheduleWorker(ScheduleWorker.Normal),1000,3000,TimeUnit.MILLISECONDS);}} CompletionService JDK8中新添加的一个类,摄像一个场景你去询问两个商品价格然后将价格保存数据库。 ExecutorServiceexecutor=Executors.newFixedThreadPool(2);//异步向电商S1询价Future<Integer>f1=executor.submit(()->getPriceByS1());//异步向电商S2询价Future<Integer>f2=executor.submit(()->getPriceByS2());//获取电商S1报价并保存r=f1.get();executor.execute(()->save(r));//获取电商S2报价并保存r=f2.get();executor.execute(()->save(r)); 上面的这个方案本身没有太大问题,但是有个地方的处理需要你注意,那就是如果获取电商 S1 报价的耗时很长,那么即便获取电商 S2 报价的耗时很短,也无法让保存 S2 报价的操作先执行,因为这个主线程都阻塞在了 f1.get(),那我们如何解决了?解决方法:结果都存入到一个阻塞队列中去。 //创建阻塞队列BlockingQueue<Integer>bq=newLinkedBlockingQueue<>();//电商S1报价异步进入阻塞队列executor.execute(()->bq.put(f1.get()));//电商S2报价异步进入阻塞队列executor.execute(()->bq.put(f2.get()));//异步保存所有报价for(inti=0;i<2;i++){Integerr=bq.take();executor.execute(()->save(r));} 在JDK8中不建议上面的工作都手动实现,JDK提供了CompletionService ,它实现原理也是内部维护了一个阻塞队列,它的核心功效就是让先执行的任务先放到结果集。当任务执行结束就把任务的执行结果加入到阻塞队列中,不同的是CompletionService是把任务执行结果的 Future 对象加入到阻塞队列中,而上面的示例代码是把任务最终的执行结果放入了阻塞队列中。CompletionService将Executor和BlockingQueue的功能融合在一起,CompletionService内部有个阻塞队列。CompletionService 接口的实现类是 ExecutorCompletionService,这个实现类的构造方法有两个,分别是: ExecutorCompletionService(Executorexecutor)ExecutorCompletionService(Executorexecutor,BlockingQueue<Future<V>>completionQueue) 这两个构造方法都需要传入一个线程池,如果不指定 completionQueue,那么默认会使用无界的 LinkedBlockingQueue。任务执行结果的 Future 对象就是加入到 completionQueue 中。 //创建线程池ExecutorServiceexecutor=Executors.newFixedThreadPool(2);//创建CompletionServiceCompletionService<Integer>cs=newExecutorCompletionService<>(executor);//异步向电商S1询价cs.submit(()->getPriceByS1());//异步向电商S2询价cs.submit(()->getPriceByS2());//将询价结果异步保存到数据库for(inti=0;i<2;i++){Integerr=cs.take().get();executor.execute(()->save(r));} 来一个整体的demo加深印象: //任务类classWorkTaskimplementsCallable<Integer>{privateStringname;publicWorkTask(Stringname){this.name=name;}@OverridepublicIntegercall(){intsleepTime=newRandom().nextInt(1000);try{Thread.sleep(sleepTime);}catch(InterruptedExceptione){e.printStackTrace();}returnsleepTime;}}publicclassCompletionCase{privatefinalintPOOL_SIZE=Runtime.getRuntime().availableProcessors();privatefinalintTOTAL_TASK=Runtime.getRuntime().availableProcessors();publicvoidselfByQueue()throwsException{longstart=System.currentTimeMillis();//统计所有任务休眠的总时长AtomicIntegercount=newAtomicInteger(0);ExecutorServicepool=Executors.newFixedThreadPool(POOL_SIZE);//创建线程池BlockingQueue<Future<Integer>>queue=newLinkedBlockingQueue<Future<Integer>>();//容器存放提交给线程池的任务,list,map,for(inti=0;i<TOTAL_TASK;i++){Future<Integer>future=pool.submit(newWorkTask("要执行的第几个任务"+i));queue.add(future);//i=0先进队列,i=1的任务跟着进}for(inti=0;i<TOTAL_TASK;i++){intsleptTime=queue.take().get();//检查线程池任务执行结果i=0先取到,i=1的后取到System.out.println("休眠毫秒数="+sleptTime+"ms");count.addAndGet(sleptTime);}pool.shutdown();System.out.println("休眠时间"+count.get()+"ms,耗时时间"+(System.currentTimeMillis()-start)+"ms");}publicvoidtestByCompletion()throwsException{longstart=System.currentTimeMillis();AtomicIntegercount=newAtomicInteger(0);//创建线程池ExecutorServicepool=Executors.newFixedThreadPool(POOL_SIZE);CompletionService<Integer>cService=newExecutorCompletionService<>(pool);//向里面扔任务for(inti=0;i<TOTAL_TASK;i++){cService.submit(newWorkTask("执行任务"+i));}//检查线程池任务执行结果for(inti=0;i<TOTAL_TASK;i++){intsleptTime=cService.take().get();System.out.println("休眠毫秒数="+sleptTime+"ms...");count.addAndGet(sleptTime);}pool.shutdown();System.out.println("休眠时间"+count.get()+"ms,耗时时间"+(System.currentTimeMillis()-start)+"ms");}publicstaticvoidmain(String[]args)throwsException{CompletionCaset=newCompletionCase();t.selfByQueue();t.testByCompletion();}} 在这里插入图片描述 常见考题 为什么用线程池? 线程池的作用? 常用的线程池模版? 7大重要参数? 4大拒绝策略? 常见线程池任务队列,如何理解有界跟无界?7.如何分配线程池个数? 单机线程池执行一般断电了如何考虑? 正在处理的实现事务功能,下次自动回滚,队列实现持久化储存,下次启动自动载入。 设定一个线程池优先级队列,Runable类要实现可对比功能,任务队列使用优先级队列 本文分享自微信公众号 - sowhat1412(sowhat9094)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

Android机运行错误INSTALL_FAILED_MEDIA_UNAVAILABLE

问题描述 现阶段正是进行示例程序内存优化测试。先后在手机上安装了好多程序,突然遇到如下问题: 使用eclipse编译成功,即将布置到android手机上运行,却报错如下: Installation error: INSTALL_FAILED_MEDIA_UNAVAILABLE Please check logcat output for more details. Launch canceled! 网络搜索找到办法。 解决办法 使用adb shell命令让手机自己选择安装在哪里。命令如下: adb shell pm setInstallLocation 0 注:不同的setInstallLocation说明: pm setInstallLocation 0 由App自行决定软件能否安装在SD卡 pm setInstallLocation 1 强制全部App安装在ROM内 pm setInstallLocation 2 强制全部App安装在SD卡 操作步骤 1、win+R快捷键打开运行窗口(或开始开始菜单,直接在搜索程序或文件框中)直接输入cmd命令。 2、cd 命令直接更改目录到platform-tools目录,比如我下载的SDK文件存放的目录为: C:\android-sdk_r08-windows\android-sdk-windows\platform-tools 3、输入adb shell命令,回车。 4、然后,再输入pm setInstallLocation 0命令,回车。 完了以后,再运行程序,测试正常。 本文转自朱先忠老师51CTO博客,原文链接:http://blog.51cto.com/zhuxianzhong/1556714,如需转载请自行联系原作者

优秀的个人博客,低调大师

JVM虚拟

Java内存结构和java内存模型的区别。往往很多人会搞起来。这里主要对这2种进行解释并进行操作。经实践会JVM调优和不会JVM调优差别确实很大,足足可以提升服务器一倍的性能。 java内存结构:所谓的堆,栈,方法区和本地方法栈 java内存模型: image.png image.png image.png image.png image.png image.png 这个堆栈分配在idea中设置的地方 image.png 新生代设置比较小的话,垃圾回收会频繁去回收,否则内存不够用,频繁回收又影响性能,不回收又会导致内存溢出,所以这个配比很关键 一般设置虚拟机内存大小都是为当前PC的内存大小,新生代和老年代的内存比例是1:2,一般老年代都会多点,因为这样可以减少垃圾回收的次数,提高性能。初始堆内存和最大堆内存设置一样。 内存溢出,有栈溢出和堆溢出,栈溢出就像下面的死循环,这个在栈当中申明的int最大只能到一定的数字 image.png image.png 总结:jvm参数调优,主要设置堆内存,主要让gc不要去频繁去回收垃圾,减少对老年代的回收。 image.png 这里题外介绍个知识点:什么叫守护线程 gc线程就是守护线程:主线程挂了,gc线程也挂了 非守护线程就是主线程挂了,但是new Thread依然在执行。 如果要把非守护线程变成守护线程,需要使用join,例:new Thread().setDeamon(); image.png 接下来介绍几个垃圾回收机制的算法 1.引用计算法 image.png 2.标记清除算法 image.png 3.复制算法。缺点是可用内存是原来内存的一半 image.png 4.标记压缩算法 image.png 5.GC分代算法 就是根据新生代和老年代进行垃圾回收,一般新生代回收的较多,老年代回收的较少,所以应该要避免老年代的gc回收,老年代回收比较慢 垃圾回收时的停顿现象 每次gc回收的时候,其他所有线程都会停顿,如果不停顿的话,那又有可能使用对象,或者新增对象,不便于垃圾清理。 垃圾收集器: 串行回收---单线程(单核回收) 并行回收---多线程(多核回收) 企业用的比较多,性能好 CMS回收---并行GC,用标记清除算法进行回收,性能是最好的,一般用并行回收就可以了 G1回收,是在jdk1.7提出来的,用的比较少 测试接口吞吐量 启动jmeter测试工具,压力测试工具,主要测试网站的吞吐量,就是每秒能被访问多少次 image.png image.png image.png image.png image.png image.png

优秀的个人博客,低调大师

硬核技术矩阵连获殊荣 东软引领智能出行新时代

2025年,智能汽车竞争从单一功能的技术突破,转向以生态融合与持续进化能力为核心的体系化较量。围绕这一趋势,东软相继推出东软A³舱行泊产品平台、东软OneCoreGo®全球车载智能出行解决方案6.0、东软NeuMind赋能体、东软NAGIC座舱软件平台等系列创新成果,形成了一套完整且可落地的“智车新基建”。岁末来临,东软技术路线与商业价值屡获认可,斩获多项行业权威大奖。 东软A³舱行泊产品平台舱驾融合引领全域智能时代 顺应电子电气架构向集中式演进的主流趋势,东软推出A³舱行泊产品平台。该平台基于单一主流SoC芯片,集座舱、仪表、行车、泊车全功能于一体,打造高集成、高可靠、高性能的舱行泊解决方案。通过算力动态分配、硬件集成与供应链简化,该平台在显著降低成本的同时,实现处理速度与数据通信效率的提升。同时全面增强复用度,有效解决了汽车智能化进程中,算力需求和成本之间的矛盾。凭借“以驾带舱”的模式创新,东软A³舱行泊产品平台正引领舱驾融合从技术趋势迈向规模化落地。 在由中国汽车工程学会与江苏省科学技术协会联合主办的2025国际汽车智能座舱大会(ICIC 2025)上,东软A³舱行泊产品平台荣获“2025年汽车智能座舱领先科技成果”荣誉。同时,在第十届铃轩奖颁奖庆典和第九届高工金球奖颁奖典礼上,东软A³舱行泊产品平台分别荣获“铃轩奖·前瞻·智能座舱系统类·优秀奖”和“高工金球奖·年度标杆产品奖”。 东软OneCoreGo®七大能力体系 重塑出行体验 东软OneCoreGo®全球车载智能出行解决方案,以全球化、AI化为核心,聚焦导航族群、AR For Car、生态、支付、智能交互等领域,赋能车企伙伴实现差异化竞争。通过持续技术创新和生态聚合,OneCoreGo®全球车载智能出行解决方案现已迭代至6.0Plus,构建七大核心能力体系,实现了“导航+支付+交互+车联+运营”的全球全链路能力闭环。同时,东软广泛聚合全球图商、娱乐、支付及车后服务等生态伙伴,推动汽车从移动工具向“生态驱动的智能生活空间”演进。 在多年赋能车企全球化的出海实践中,东软OneCoreGo®全球车载智能出行解决方案实现了大规模、稳定可靠的车载部署与运营,获颁“铃轩奖·量产·车用软件类·金奖”。同时,凭借卓越的技术实力、全球化的产品布局与出色的出海实践,东软OneCoreGo®全球车载智能出行解决方案荣获“高工金球奖·出海领航奖”和“2025金辑奖·最佳出海实践奖”。 NAGIC与NeuMind打造智能汽车软实力双翼 在智能汽车进化的更深处,软件与AI技术的协同已成为决定智能出行体验的重要因素。东软面向全球市场,推出兼具低成本与高性能显著优势的座舱软件解决方案——NAGIC座舱软件平台。不仅全面覆盖全球各类典型的基础座舱功能,产品更强化了AVM(全景环视系统)、DMS(驾驶员监测系统)等舱内外视觉技术能力,同时广泛整合丰富的全球生态资源,为车企伙伴提供极具竞争力的东软方案。在第九届高工金球奖颁奖典礼上,产品荣获“年度技术突破奖”。 而作为汽车的“AI大脑”,东软NeuMind赋能体基于东软“融智”AI实施框架,融合多种基础AI模型的智能化能力,提供场景化智能服务引擎与个性化用户体验定制。产品可集成智能座舱、智能辅助驾驶、智能车身、车联网等关键模块,贯通感知、决策与进化链路,将AI转化为可量产的标准化能力,为车企提供全栈式智能化解决方案。在2025高工智能汽车产业峰会上,产品荣获“年度技术领航奖”。 奖项的获得,既是业界对东软产品技术领先性的共识,也是对东软推动产业演进与价值升维的肯定。未来,随着智能汽车竞争进入“体系化决胜”新阶段,东软将持续通过软硬件融合、AI全栈赋能与生态协同,构建新一代智能出行体系,推动全球汽车产业迈向可持续进化的未来。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册