我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java中实现线程池的原理是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java中实现线程池的原理是什么

Java中实现线程池的原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

01.***制线程的缺点

多线程的软件设计方法确实可以***限度地发挥多核处理器的计算能力,提高生产系统的吞吐量和性能。但是,若不加控制和管理的随意使用线程,对系统的性能反而会产生不利的影响。

一种最为简单的线程创建和回收的方法类似如下:

new Thread(new Runnable() {             @Override             public void run() {                 //do sth             }         }).start();

以上代码创建了一条线程,并在run()方法结束后,自动回收该线程。在简单的应用系统中,这段代码并没有太多问题。但是在真实的生产环境中,系统由于真实环境的需要,可能会开启很多线程来支撑其应用。而当线程数量过大时,反而会耗尽CPU和内存资源。

首先,虽然与进程相比,线程是一种轻量级的工具,但其创建和关闭依然需要花费时间,如果为每一个小的任务都创建一个线程,很有可能出现创建和销毁线程所占用的时间大于该线程真实工作所消耗的时间,反而会得不偿失。

其次,线程本身也是要占用内存空间的,大量的线程会抢占宝贵的内部资源。

因此,在实际生产环境中,线程的数量必须得到控制。盲目地大量创建线程对系统性能是有伤害的。

02.简单的线程池实现

下面给出一个最简单的线程池,该线程池不是一个完善的线程池,但已经实现了一个基本线程池的核心功能,有助于快速理解线程池的实现。

线程池的实现

public class ThreadPool {     private static ThreadPool instance = null;      //空闲的线程队列     private List<PThread> idleThreads;     //已有的线程总数     private int threadCounter;     private boolean isShutDown = false;      private ThreadPool() {         this.idleThreads = new Vector<>(5);         threadCounter = 0;     }      public int getCreatedThreadCounter() {         return threadCounter;     }      //取得线程池的实例     public synchronized static ThreadPool getInstance() {         if (instance == null) {             instance = new ThreadPool();         }         return instance;     }      //将线程池放入池中     protected synchronized void repool(PThread repoolingThread) {         if (!isShutDown) {             idleThreads.add(repoolingThread);         } else {             repoolingThread.shutDown();         }     }      //停止池中所有线程     public synchronized void shutDown() {         isShutDown = true;         for (int threadIndex = 0; threadIndex < idleThreads.size(); threadIndex++) {             PThread pThread = idleThreads.get(threadIndex);             pThread.shutDown();         }     }      //执行任务     public synchronized void start(Runnable target) {         PThread thread = null;         //如果有空闲线程,则直接使用         if (idleThreads.size() > 0) {             int lastIndex = idleThreads.size() - 1;             thread = idleThreads.get(lastIndex);             idleThreads.remove(thread);             //立即执行这个任务             thread.setTarget(target);         }//没有空闲线程,则创建线程         else {             threadCounter++;             //创建新线程             thread = new PThread(target, "PThread #" + threadCounter, this);             //启动这个线程             thread.start();         }     }  }

要实现上面的线程池,就需要一个永不退出的线程与之配合。PThread就是一个这样的线程。它的主体部分是一个***循环,该线程在手动关闭前永不结束,并一直等待新的任务到达。

public class PThread extends Thread {     //线程池     private ThreadPool pool;     //任务     private Runnable target;     private boolean isShutDown = false;     private boolean isIdle = false; //是否闲置     //构造函数     public PThread(Runnable target,String name, ThreadPool pool){         super(name);         this.pool = pool;         this.target = target;     }      public Runnable getTarget(){         return target;     }      public boolean isIdle() {         return isIdle;     }      @Override     public void run() {         //只要没有关闭,则一直不结束该线程         while (!isShutDown){             isIdle =  false;             if (target != null){                 //运行任务                 target.run();             }             try {                 //任务结束了,到闲置状态                 isIdle = true;                 pool.repool(this);                 synchronized (this){                     //线程空闲,等待新的任务到来                     wait();                 }             } catch (InterruptedException e) {                 e.printStackTrace();             }             isIdle = false;         }     }      public synchronized void setTarget(Runnable newTarget){         target = newTarget;         //设置了任务之后,通知run方法,开始执行这个任务         notifyAll();     }      //关闭线程     public synchronized void shutDown(){         isShutDown = true;         notifyAll();     }  }

测试Main方法

public static void main(String[] args) throws InterruptedException {        for (int i = 0; i < 1000; i++) {            ThreadPool.getInstance().start(new Runnable() {                @Override                public void run() {                    try {                        //休眠100ms                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            });        }    }

03ThreadPoolExecutor

为了能够更好地控制多线程,JDK提供了一套Executor框架,帮助开发人员有效地进行线程控制。Executor框架无论是newFixedThreadPool()方法、newSingleThreadExecutor()方法还是newCachedThreadPool()方法,其内部实现均使用了  ThreadPoolExecutor:

public static ExecutorService newCachedThreadPool() {         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                       60L, TimeUnit.SECONDS,                                       new SynchronousQueue<Runnable>());     }          public static ExecutorService newFixedThreadPool(int nThreads) {         return new ThreadPoolExecutor(nThreads, nThreads,                                       0L, TimeUnit.MILLISECONDS,                                       new LinkedBlockingQueue<Runnable>());     }          public static ExecutorService newSingleThreadExecutor() {         return new FinalizableDelegatedExecutorService             (new ThreadPoolExecutor(1, 1,                                     0L, TimeUnit.MILLISECONDS,                                     new LinkedBlockingQueue<Runnable>()));     }

由以上线程池的实现代码可以知道,它们只是对 ThreadPoolExecutor 类的封装。为何 ThreadPoolExecutor  类有如此强大的功能?来看一下 ThreadPoolExecutor 最重要的构造方法。

3.1 构造方法

ThreadPoolExecutor最重要的构造方法如下:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

方法参数如下:

Java中实现线程池的原理是什么

ThreadPoolExecutor的使用示例,通过execute()方法提交任务。

public static void main(String[] args) {         ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());         for (int i = 0; i < 10; i++) {             executor.execute(new Runnable() {                 @Override                 public void run() {                     System.out.println(Thread.currentThread().getName());                 }             });         }         executor.shutdown();     }

或者通过submit()方法提交任务

public static void main(String[] args) throws ExecutionException, InterruptedException {         ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());         List<Future> futureList = new Vector<>();         //在其它线程中执行100次下列方法         for (int i = 0; i < 100; i++) {             futureList.add(executor.submit(new Callable<String>() {                 @Override                 public String call() throws Exception {                     return Thread.currentThread().getName();                 }             }));         }         for (int i = 0;i<futureList.size();i++){             Object o = futureList.get(i).get();             System.out.println(o.toString());         }         executor.shutdown();     }

运行结果:

... pool-1-thread-4 pool-1-thread-3 pool-1-thread-2

下面主要讲解ThreadPoolExecutor的构造方法中workQueue和RejectedExecutionHandler参数,其它参数都很简单。

3.2 workQueue任务队列

用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。

  • ArrayBlockingQueue: 是一个基于数组结构的有界阻塞队列,按FIFO原则进行排序

  • LinkedBlockingQueue:  一个基于链表结构的阻塞队列,吞吐量高于ArrayBlockingQueue。静态工厂方法Excutors.newFixedThreadPool()使用了这个队列

  • SynchronousQueue:  一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量高于LinkedBlockingQueue,静态工厂方法Excutors.newCachedThreadPool()使用了这个队列

  • PriorityBlockingQueue: 一个具有优先级的***阻塞队列。

3.3 RejectedExecutionHandler饱和策略

当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略还处理新提交的任务。它可以有如下四个选项:

  • AbortPolicy : 直接抛出异常,默认情况下采用这种策略

  • CallerRunsPolicy : 只用调用者所在线程来运行任务

  • DiscardOldestPolicy : 丢弃队列里最近的一个任务,并执行当前任务

  • DiscardPolicy : 不处理,丢弃掉

更多的时候,我们应该通过实现RejectedExecutionHandler 接口来自定义策略,比如记录日志或持久化存储等。

3.4 submit()与execute()

可以使用execute和submit两个方法向线程池提交任务。

execute方法用于提交不需要返回值的任务,利用这种方式提交的任务无法得知是否正常执行

submit方法用于提交一个任务并带有返回值,这个方法将返回一个Future类型对象。可以通过这个返回对象判断任务是否执行成功,并且可以通过future.get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成。

3.5 shutdown()与shutdownNow()

可以通过调用 shutdown() 或 shutdownNow() 方法来关闭线程池。它们的原理是遍历线程池中的工作线程,然后逐个调用线程的  interrupt 方法来中断线程,所以无法响应中断的任务可能永远无法停止。

这俩方法的区别是,shutdownNow() 首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而  shutdown() 只是将线程池的状态设置成 SHUTDOWN 状态,然后中断所有没有正在执行任务的线程。

只要调用了这两个关闭方法的任意一个,isShutdown 方法就会返回 true。当所有的任务都已关闭了,才表示线程池关闭成功,这时调用  isTerminaced 方法会返回 true。

通常调用 shutdown() 方法来关闭线程池,如果任务不一定要执行完,则可以调用 shutdownNow() 方法。

3.6 合理配置线程池

要想合理地配置线程池,首先要分析任务特性

  • 任务的性质:CPU密集型任务、IO密集型任务和混合型任务。

  • 任务的优先级:高、中和低。

  • 任务的执行时间:长、中和短。

  • 任务的依赖性:是否依赖其他系统资源,如数据库连接。

性质不同的任务可以用不同规模的线程池分开处理。

CPU密集型任务应该配置尽可能少的线程,如配置N+1个线程,N位CPU的个数。

而IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*N。

混合型任务,如果可以拆分,将其拆分成一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐量将高于串行执行的吞吐量。如果这两个任务执行的时间相差很大,则没有必要进行分解。可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。

优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先执行。

3.7 线程池的监控

由于大量的使用线程池,所以很有必要对其进行监控。可以通过继承线程池来自定义线程池,重写线程池的beforeExecute、afterExecute 和  terminated 方法,也可以在任务执行前,执行后和线程池关闭前执行一些代码来进行监控。在监控线程池的时候可以使用一下属性:

(1) taskCount:线程池需要执行的任务数量

(2) completedTaskCount:线程池在运行过程中已完成的任务数量,小于或等于taskCount

(3) largestPoolSize:  线程池里曾经创建过***的线程数量。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池***大小,则表示线程池曾经满过。

(4) getPoolSize:线程池的线程数量。如果线程池不销毁的话,线程池里的线程不会自动销毁,所以这个大小只增不减。

(5) getActiveCount:获取活动的线程数

04Executor多线程框架

ThreadPoolExecutor 表示一个线程池,Executors 类则扮演着线程池工厂的角色,通过 Executors  可以取得一个特定功能的线程池。

使用 Executors 框架实现上节中的例子,其代码如下:

public static void main(String[] args) {         //新建一个线程池         ExecutorService executor = Executors.newCachedThreadPool();         //在其它线程中执行100次下列方法         for (int i = 0; i < 100; i++) {             executor.execute(new Runnable() {                 @Override                 public void run() {                     System.out.println(Thread.currentThread().getName());                 }             });         }         //执行完关闭         executor.shutdown();     }

4.1 Executors框架的结构

1.任务

包括被执行任务需要实现的接口:Runnable 接口或 Callable 接口。

2.任务的执行

包括任务执行机制的核心接口 Executor,以及继承自 Executor 的ExecutorService 接口。Executor框架有两个关键类实现了  ExecutorService 接口(ThreadPoolExecutor 和 ScheduledThreadPoolExecutor)。

3.异步计算的结果

包括接口 Future 和实现Future接口的FutureTask类。

4.2 Executors工厂方法

Executors工厂类的主要方法:

public static ExecutorService newFixedThreadPool(int nThreads)

该方法返回一个固定线程数量的线程池,该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。

public static ExecutorService newSingleThreadExecutor()

该方法返回一个只有一个线程的线程池。若多余一个任务被提交到线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。

public static ExecutorService newCachedThreadPool()

该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。但所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。

public static ScheduledExecutorService newSingleThreadScheduledExecutor()

该方法返回一个ScheduledExecutorService对象,线程池大小为1。ScheduledExecutorService接口在ExecutorService接口之上扩展了在给定时间执行某任务的功能,如在某个固定的延时之后执行,或者周期性执行某个任务。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

该方法也返回一个 ScheduledExecutorService 对象,但该线程池可以指定线程数量。

4.3 ThreadPoolExecutor与ScheduledThreadPoolExecutor

在前面提到了Executors 类扮演着线程池工厂的角色,通过 Executors 可以取得一个特定功能的线程池。Executors  工厂类的主要方法可以创建 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 线程池。

关于ThreadPoolExecutor ,前面第3节已经详细叙述。ScheduledThreadPoolExecutor  也是ExecutorService接口的实现类,可以在给定的延迟后运行命令,或者定期执行命令。ScheduledThreadPoolExecutor 比  Timer 更灵活,功能更强大。

4.4 Future与FutureTask

上面的示例中使用 execute()  方法提交任务,用于提交不需要返回值的任务。如果我们需要获取执行任务之后的返回值,可以使用submit()方法。

示例代码:

public static void main(String[] args) throws InterruptedException, ExecutionException {         //新建一个线程池         ExecutorService executor = Executors.newCachedThreadPool();         List<Future> futureList = new Vector<>();         //在其它线程中执行100次下列方法         for (int i = 0; i < 100; i++) {             futureList.add(executor.submit(new Callable<String>() {                 @Override                 public String call() throws Exception {                     return Thread.currentThread().getName()+" "+System.currentTimeMillis()+" ";                 }             }));         }         for (int i = 0;i<futureList.size();i++){             Object o = futureList.get(i).get();             System.out.println(o.toString()+i);         }         executor.shutdown();     }

运行结果:

... pool-1-thread-11 1537872778612 96 pool-1-thread-11 1537872778613 97 pool-1-thread-10 1537872778613 98 pool-1-thread-10 1537872778613 99

到这里,就不得不提Future接口与FutureTask实现类,它们代表异步计算的结果。

Future<T> submit(Callable<T> task) Future<?> submit(Runnable task); Future<T> submit(Runnable task, T result);

当我们submit()提交后,会返回一个Future对象,到JDK1.8,返回的实际是FutureTask实现类。submit() 方法支持  Runnable 或 Callable 类型的参数。Runnable 接口 和Callable 接口的区别就是 Runnable 不会返回结果,Callable  会返回结果。

主线程可以执行 futureTask.get() 方法来阻塞当前线程直到任务执行完成,任务完成后返回任务执行的结果。

futureTask.get(long timeout, TimeUnit unit)  方法则会阻塞当前线程一段时间立即返回,这时候有可能任务没有执行完。

主线程也可以执行 futureTask.cancel(boolean mayInterruptIfRunning) 来取消此任务的执行。

futureTask.isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。

futureTask.isDone方法表示任务是否已经完成,若任务完成,则返回true。

看完上述内容,你们掌握Java中实现线程池的原理是什么的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网行业资讯频道,感谢各位的阅读!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java中实现线程池的原理是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java中实现线程池的原理是什么

Java中实现线程池的原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。01.***制线程的缺点多线程的软件设计方法确实可以***限度地发挥多核处理器的计算能力,提高生产
2023-06-16

Java中线程池的实现原理是什么

这篇文章给大家介绍Java中线程池的实现原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。线程池是什么?我们可以利用java很容易创建一个新线程,同时操作系统创建一个线程也是一笔不小的开销。所以基于线程的复用,就
2023-05-31

Java线程池实现原理是什么

这篇文章主要讲解了“Java线程池实现原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java线程池实现原理是什么”吧!一、线程池参数1、corePoolSize(必填):核心线程数
2023-06-28

Java线程池实现原理是什么及怎么使用

这篇文章主要讲解了“Java线程池实现原理是什么及怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java线程池实现原理是什么及怎么使用”吧!1. 为什么要使用线程池使用线程池通常由以
2023-07-04

android线程池的原理是什么

Android线程池的原理是通过管理和调度线程来实现并发执行任务的机制。线程池主要由线程池管理器、工作队列和线程池的线程组成。线程池管理器:线程池管理器负责创建、销毁和管理线程池。它根据任务的类型和优先级来决定将任务分配给线程池中的线程执行
2023-09-23

Python中的进程池和线程池的适用场景和实现原理是什么?

Python中的进程池和线程池的适用场景和实现原理是什么?引言:在编写程序时,为了提高执行效率,经常会使用并发编程来同时执行多个任务。Python提供了进程池和线程池这两种用于并发处理任务的工具。本文将详细介绍进程池和线程池的适用场景和实现
2023-10-22

java线程池实现的方法是什么

Java中线程池的实现方法是通过使用java.util.concurrent包中的ThreadPoolExecutor类来创建和管理线程池。具体步骤如下:1. 使用Executors类的静态方法创建一个线程池对象,可以选择使用的线程池类型(
2023-10-11

java中什么是线程池

本篇文章为大家展示了java中什么是线程池,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. 客户端开发;4.
2023-06-14

SpringBoot线程池和Java线程池的使用和实现原理解析

这篇文章主要介绍了SpringBoot线程池和Java线程池的用法和实现原理,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-15

Java中ThreadLocal线程变量的实现原理是什么

这篇文章主要介绍了Java中ThreadLocal线程变量的实现原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java中ThreadLocal线程变量的实现原理是什么文章都会有所收获,下面我们一起来看
2023-07-02

深入理解Java编程线程池的实现原理

在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间
2023-05-30

java线程池的实现原理源码分析

这篇文章主要介绍“java线程池的实现原理源码分析”,在日常操作中,相信很多人在java线程池的实现原理源码分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java线程池的实现原理源码分析”的疑惑有所帮助!
2023-06-30

java线程池的实现原理、优点与风险、以及4种线程池实现

这篇文章主要介绍了java线程池的实现原理、优点与风险、以及4种线程池实现包括了:配置线程池大小配置,线程池的实现原理等,需要的朋友可以参考下
2023-02-18

什么是java线程池

使用线程池的好处有很多,比如节省系统资源的开销,节省创建和销毁线程的时间等,当我们需要处理的任务较多时,就可以使用线程池,可能还有很多用户不知道Java线程池如何使用?今天给大家分享Java四种线程池的使用方法。线程池介绍:线程池是一种多线程处理形式,处理过程
什么是java线程池
2017-06-28

java线程池是什么

java的线程池是什么,有哪些类型,作用分别是什么 (推荐学习:java课程)线程池是一种多线程处理形式,处理过程中将任务添加队列,然后在创建线程后自动启动这些任务,每个线程都使用默认的堆栈大小,以默认的优先级运行,并处在多线程单元中,如果
java线程池是什么
2016-06-22

java 中多线程的原理是什么

今天就跟大家聊聊有关java 中多线程的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1.基本概念程序、进程、线程程序(program)是为完成特定任务、用某种语言编写的一
2023-06-20

java中多线程的原理是什么

java中多线程的原理是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。java基本数据类型有哪些Java的基本数据类型分为:1、整数类型,用来表示整数的数据
2023-06-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录