当前位置: 首页 > news >正文

郑州o2o网站建设汉狮百度百科怎么创建自己

郑州o2o网站建设汉狮,百度百科怎么创建自己,西宁网站搭建,中国人在俄罗斯做网站需要多少卢布目录 一、继承 Thread 类创建线程 步骤 示例代码 原理 二、实现 Runnable 接口创建线程 步骤 示例代码 原理 三、实现 Callable 接口创建线程 步骤 示例代码 原理 与Runnable接口相比的不同之处 四、使用线程池创建线程 步骤 示例代码(使用 Executo…

目录

一、继承 Thread 类创建线程

步骤

示例代码

原理

二、实现 Runnable 接口创建线程

步骤

示例代码

原理

三、实现 Callable 接口创建线程

步骤

示例代码

原理

与Runnable接口相比的不同之处

四、使用线程池创建线程

步骤

示例代码(使用 Executors.newFixedThreadPool)

原理

线程池的优势

自定义线程池

五、总结


        在 Java 编程中,多线程是一项非常重要的技术,它能够充分利用计算机的多核处理器资源,提高程序的执行效率和响应性。本文将详细介绍 Java 中创建多线程的四种方式,包括继承 Thread 类、实现 Runnable 接口、实现 Callable 接口以及使用线程池,并对每种方式的原理、代码示例和适用场景进行深入剖析。

一、继承 Thread 类创建线程

步骤

  • 创建一个类继承自 Thread 类。
  • 重写 run 方法,在 run 方法中定义线程要执行的任务。
  • 创建该类的实例,然后调用 start 方法启动线程。

示例代码

class MyThread extends Thread{// Ctrl + o// 展示所有的可以重写的方法@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("数据:"+i);}}
}
public class Demo01 {/***  第一种方案,继承Thread类  重写run方法 实现* @param args*/public static void main(String[] args) {// 在Main方法中,启动了一个子线程,子线程什么时候工作MyThread thread = new MyThread();thread.start();// 启动一个线程,调用start方法,不要调用run方法// 一个线程类,是可以创建多个不同的子线程的MyThread thread2 = new MyThread();thread2.start();// 启动一个线程,调用start方法,不要调用run方法// 主线程,直接运行代码   会出现子线程和主线程抢占资源的情况for (int i = 10; i < 100; i++) {System.err.println("Main:"+i);}}
}

原理

        当调用 start 方法时,会在新的线程中执行 run 方法。需要注意的是,start 方法只是启动线程,不会立即执行 run 方法。线程要等待获取 CPU 资源后才会执行 run 方法,而且在执行过程中可能会被其他线程抢占 CPU 资源。

二、实现 Runnable 接口创建线程

步骤

  • 创建一个类实现 Runnable 接口。
  • 实现 run 方法,在 run 方法中定义线程要执行的任务。
  • 创建 Runnable 接口实现类的实例,将其作为参数传递给 Thread 类的构造函数,然后调用 start 方法启动线程。

示例代码

class A implements Runnable{@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}}
}
public class Demo03 {/***  多线程创建的第二种方式,使用 Runnable接口*  该接口还需要传递给Thread类才能启动,否则自己启动不了**  两种方式:推荐使用第二种*   1、Thread类是一个线程类,它只需要管理好线程就行了,不需要管业务怎么写*   2、具体的业务可以交给Runnable接口实现*   3、java是单继承的,继承了Thread,就无法继承别的类了,但是可以实现多个接口。*/public static void main(String[] args) {A a = new A();new Thread(a).start();// Runnable接口本身就是一个函数式接口,就可以使用lambda表达式,代码可以简化为如下:new Thread( ()-> {for (int i = 0; i < 1000; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}}).start();for (int i = 0; i < 1000; i++) {System.err.println(Thread.currentThread().getName()+":"+i);}}
}

原理

        Runnable 接口定义了一个无返回值的 run 方法,用于包含线程要执行的代码。Thread 类的构造函数可以接收一个 Runnable 接口的实现对象,当调用 Thread 的 start 方法时,会在新的线程中执行 Runnable 对象的 run 方法。这种方式比继承 Thread 类更灵活,因为 Java 是单继承的,如果一个类已经继承了其他类,就不能再继承 Thread 类了,但是可以实现 Runnable 接口来实现多线程。

三、实现 Callable 接口创建线程

步骤

  • 创建一个类实现 Callable 接口,该接口是一个函数式接口,有一个泛型参数,用于指定返回值类型。
  • 实现 call 方法,在 call 方法中定义线程要执行的任务,并返回一个结果。
  • 创建 Callable 接口实现类的实例,将其包装在一个 FutureTask 对象中,FutureTask 实现了 RunnableFuture 接口,而 RunnableFuture 接口继承了 Runnable 和 Future 接口。
  • 将 FutureTask 对象作为参数传递给 Thread 类的构造函数,然后调用 start 方法启动线程。可以通过 FutureTask 的 get 方法获取 call 方法的返回结果。

示例代码

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;class MyCall implements Callable<Integer>{@Overridepublic Integer call() throws Exception {return 200;}
}class MyRun implements Runnable{@Overridepublic void run() {System.out.println("我是子线程....");}
}
public class Demo08 {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<Integer> futureTask = new FutureTask<>(new MyCall());new Thread(futureTask,"计算线程").start();Integer i = futureTask.get();System.out.println(i);// --------------------------------------new Thread(new MyRun()).start();// ------------------使用callable 模拟 子线程进行大量计算并返回结果------------------FutureTask<Integer> f1 = new FutureTask<>(()->{System.out.println(Thread.currentThread().getName()+"  come in callable");TimeUnit.SECONDS.sleep(4);return 1024;});FutureTask<Integer> f2 = new FutureTask<>(()->{System.out.println(Thread.currentThread().getName()+"  come in callable");TimeUnit.SECONDS.sleep(4);return 2048;});new Thread(f1,"线程一:").start();new Thread(f2,"线程二:").start();while(!f1.isDone()){System.out.println("f1  wait中.....");}while(!f2.isDone()){System.out.println("f2  wait中.....");}// 其实 get 获取不到值会一直阻塞,直到获取到值为止int a = f1.get();int b = f2.get();System.out.println(a+b);}
}

原理

        Callable 接口与 Runnable 接口类似,但是 Callable 接口的 call 方法可以有返回值,并且可以抛出异常。FutureTask 用于包装 Callable 对象,它可以在未来某个时刻获取 call 方法的返回结果。通过这种方式,可以实现有返回值的多线程任务。

与Runnable接口相比的不同之处

(1)是否有返回值

(2)是否抛异常
(3)落地方法不一样,一个是run,一个是call

四、使用线程池创建线程

步骤

  • 通过 Executors 工具类的静态方法(如 newFixedThreadPoolnewCachedThreadPoolnewSingleThreadExecutor)创建一个线程池对象,或者直接使用 ThreadPoolExecutor 类来创建自定义的线程池。
  • 创建 Runnable 或 Callable 接口实现类的实例,作为任务提交给线程池。对于 Runnable 任务,可以使用 execute 方法提交;对于 Callable 任务,可以使用 submit 方法提交。

示例代码(使用 Executors.newFixedThreadPool

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThreadPoolDemo {public static void main(String[] args) {//       ExecutorService threadPool =  Executors.newFixedThreadPool(5); //一个银行网点,5个受理业务的窗口
//       ExecutorService threadPool =  Executors.newSingleThreadExecutor(); //一个银行网点,1个受理业务的窗口ExecutorService threadPool =  Executors.newCachedThreadPool(); //一个银行网点,可扩展受理业务的窗口//10个顾客请求try {for (int i = 1; i <=10; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t 办理业务");});}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();}}
}

原理

        线程池用于管理和复用线程。当提交一个任务到线程池时,线程池会根据自身的状态和配置来决定如何处理任务。如果线程池中有空闲线程,就会将任务分配给空闲线程执行;如果没有空闲线程且线程数量未达到最大限制,就会创建新的线程来执行任务;如果线程数量达到最大限制且任务队列已满,会根据线程池的拒绝策略来处理任务。这样可以有效地控制线程的数量,提高系统的性能和资源利用率,减少线程创建和销毁的开销。

线程池的优势

线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。

它的主要特点为:线程复用;控制最大并发数;管理线程。

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的销耗。

第二:提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行。

第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

Java中的线程池是通过Executor框架实现的,该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor这几个类。

经常使用的线程池做法

1、Executors.newFixedThreadPool(int)

执行长期任务性能好,创建一个线程池,一池有N个固定的线程,有固定线程数的线程

newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的是LinkedBlockingQueue

2、Executors.newSingleThreadExecutor()

一个任务一个任务的执行,一池一线程。

newSingleThreadExecutor 创建的线程池corePoolSize和maximumPoolSize值都是1,它使用的是LinkedBlockingQueue

3、Executors.newCachedThreadPool()

执行很多短期异步任务,线程池根据需要创建新线程,但在先前构建的线程可用时将重用它们。可扩容,遇强则强。

newCachedThreadPool创建的线程池将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,它使用的是SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。

自定义线程池


虽然根据API 我们能很轻松的使用到线程池,但是在实际开发中我们经常自定义线程池,怎么做呢?

参数说明

1、corePoolSize:线程池中的常驻核心线程数
2、maximumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于1
3、keepAliveTime:多余的空闲线程的存活时间   
当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时, 多余线程会被销毁直到只剩下corePoolSize个线程为止。
4、unit:keepAliveTime的单位 
5、workQueue:任务队列,被提交但尚未被执行的任务  就是我们之前讲的阻塞队列
6、threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认的即可
7、handler:拒绝策略,表示当队列满了,并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝
请求执行的runnable的策略

线程池的拒绝策略

AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行。
CallerRunsPolicy:“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,俗称从哪儿来到哪儿去。
DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加人队列中尝试再次提交当前任务。
DiscardPolicy:该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略。

以上内置拒绝策略均实现了RejectedExecutionHandle接口

1、在创建了线程池后,线程池中的线程数为零。

2、当调用execute()方法添加一个请求任务时,线程池会做出如下判断:

        2.1如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;

        2.2如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列;

        2.3如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;

        2.4如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。

3、当一个线程完成任务时,它会从队列中取下一个任务来执行。

4、当一个线程无事可做超过一定的时间(keepAliveTime)时,线程会判断:

        如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。

        所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小。

 示例代码

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
/*** 线程池* Arrays* Collections* Executors*/
public class MyThreadPoolDemo {public static void main(String[] args) {ExecutorService threadPool = new ThreadPoolExecutor(2,5,2L,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),//new ThreadPoolExecutor.AbortPolicy()//new ThreadPoolExecutor.CallerRunsPolicy()//new ThreadPoolExecutor.DiscardOldestPolicy()new ThreadPoolExecutor.DiscardOldestPolicy());//10个顾客请求try {for (int i = 1; i <= 10; i++) {threadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "\t 办理业务");});}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();}}
}

五、总结

        Java 提供了多种创建多线程的方式,每种方式都有其特点和适用场景。继承 Thread 类简单直接,适用于简单的线程任务;实现 Runnable 接口更加灵活,适合在已有类层次结构中使用多线程;实现 Callable 接口可用于需要获取线程执行结果的场景;使用线程池则可以高效地管理和复用线程,适用于需要大量线程处理任务的情况,并且可以通过合理配置线程池参数来优化系统性能。在实际开发中,需要根据具体的需求和场景选择合适的多线程创建方式,以充分发挥多线程编程的优势,提高程序的质量和效率。

http://www.mmbaike.com/news/51247.html

相关文章:

  • 上海哪里有做网站的产品推广方案ppt
  • 广州住建厅官方网站写软文用什么软件
  • wordpress根目录文件有哪些河北seo诊断培训
  • 集团网站建设的要求上海推广系统
  • 本地如何搭建多个网站做测试培训网络营销机构
  • 怎样给网站做软件测试网络营销策划论文
  • wordpress 网站地图类资源优化网站排名
  • 网站制作最seo专家招聘
  • ruby 做网站专业网站优化公司
  • 如何搭建个人网站网站推广软件排名
  • 制作app需要先做网站百度图片识别在线使用
  • dw创建网站相册外链大全
  • 哪个网站可以做头像的百度统计平台
  • php网站 上传安卓优化大师官方版
  • 网站做的文字乱码智慧软文发布系统
  • 重庆石桥铺网站建设公司南昌seo排名扣费
  • 网站建设什么是开发实施实施电脑培训班一般要学多久
  • 专业建站教程东莞网站建设
  • 重庆网站建设的价格低网站访问量排行榜
  • 一站式网站建设方案长春seo
  • 网站建设的目录浏览免费推广网站大全下载
  • 网站建设捌金手指专业1图片外链生成工具
  • 网站建设管理及维护牡丹江网站seo
  • 响应式网站建设济南班级优化大师的优点
  • 杭州萧山区专门做网站的公司seo外包网站
  • 做时时彩开奖网站犯法吗win7系统优化工具
  • 网站空间国外那个好口碑seo推广公司
  • 服务器网站别名设置百度快速排名培训
  • 铜陵做网站的公司seo全称是什么
  • 做网站推广的难点、电子商务是干什么的