创建并启动线程的6种方式

  • 继承Thread类创建线程
  • 实现Runnable接口创建线程
  • 使用Callable和FutureTask创建线程
  • 使用线程池,例如用Executor框架
  • Spring实现多线程(底层是线程池)
  • 定时器Timer (底层封装了一个TimerThread对象)

1、继承Thread类创建线程

1.1继承Thread类方式创建线程的实现步骤:

步骤:

1) 定义一个类A继承于java.lang.Thread类

2)在A类中覆盖Thread类中的run方法

3)我们在run方法中编写需要执行的操作---->run方法里的,线程执行体

4)在main方法(线程)中,创建线程对象,并启动线程

  • 创建线程类对象: A类 a = new A类();
  • 调用线程对象的start方法: a.start();//启动一个线程

注意:千万不要调用run方法,如果调用run方法好比是对象调用方法,依然还是只有一个线程,并没有开启新的线程。

1.2需求:使用两个线程实现边听歌边打游戏

实现代码:

//音乐线程
public class MusicThread {
public static void main(String[] args) {
//创建游戏线程对象
GameThread game = new GameThread();
//启动游戏线程
game.start();
while(true){
System.out.println(Thread.currentThread().getName()+"听音乐!");
}
}
}
//游戏线程
class GameThread extends Thread{
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName()+"打游戏!");
}
}
}

注意:有的小伙伴可能觉得音乐线程没有启动,在这里其实音乐线程已经启动起来了,而启动音乐线程的对象就是我们的JVM,此处main方法其实启动的时候会创建一个主线程去执行main方法,所以我在这里使用主线程作为了我的音乐线程。

2、实现Runnable接口创建线程

2.1实现Runnable接口方式创建线程的实现步骤:

1)定义一个类A实现于java.lang.Runnable接口,注意A类不是线程类。 2)在A类中覆盖Runnable接口中的run方法。 3) 我们在run方法中编写需要执行的操作---->run方法里的,线程执行体。 4)在main方法(线程)中,创建线程对象,并启动线程。

  • 创建线程类对象: Thread t = new Thread(new A());
  • 调用线程对象的start方法: t.start();

2.2需求:使用两个线程实现边听歌边打游戏

实现代码:

//音乐线程
public class MusicThread {
public static void main(String[] args) {
//创建游戏线程对象
Thread game = new Thread(new Game());
//启动游戏线程
game.start();
while(true){
System.out.println(Thread.currentThread().getName()+"听音乐!");
}
}
}//游戏
class Game implements Runnable{
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName()+"打游戏!");
}
}
}

2.3 继承方式和实现方式的区别

1)继承方式是一个类继承了Thread后成为线程类的子类,实现方式是一个类实现Runnable接口,但是这个类不是线程类,因为该类没有start等方法。

2)启动的时候继承方式直接调用自己的start方法,实现方式是借助了Thread中的start方法启动的,自身没有start方法。

3)继承方式调用的run方法是通过方法覆盖,通过继承方式实现的,运行的时候先找子类,没有最后才运行父类的run方法。实现方式是执行Thread的run方法,而Thread中的run方法调用了实现类中的run方法,使用过组合关系的方法调用实现的。

3、实现 Callable 接口

3.1使用Callable和FutureTask创建线程的实现步骤:

1)定义一个Callable接口的实现类

2)创建Callable实现类对象传递给FutureTask构造器

3)将FutureTask对象传递给Thread构造器

4)Thread对象调用start方法启动线程

5)通过FutureTask对象的get方法获取线程运行的结果

注意: Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

使用场景:使用多线程计算结果并返回该结果。

3.2需求:使用2个线程异步计算1-1000,000内之和

实现代码:

public class CallableDemo {
public static void main(String[] args) throws Exception  {
//1.创建并启动线程
Callable<Integer> call1 = new CallableImpl(0, 50000);
Callable<Integer> call2 = new CallableImpl(50001, 100000);FutureTask<Integer> f1 = new FutureTask<>(call1);
FutureTask<Integer> f2 = new FutureTask<>(call2);new Thread(f1).start();
new Thread(f2).start();
//2.获取每一个线程的结果
int ret1 = f1.get();
int ret2 = f2.get();
int ret= ret1+ret2;
System.out.println(ret);
}
}
class CallableImpl implements Callable<Integer>{private int min;
private int max;public CallableImpl(int min, int max) {
this.min = min;
this.max = max;
}@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = min; i <= max; i++) {
sum+=i;
}
return sum;
}
}

3.3Callable和Runnable的区别如下:

Callable定义的方法是call,而Runnable定义的方法是run。

Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。

Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常。

注意:

FutureTask为Runnable的实现类

FutureTask可以视为一个闭锁(门闩),因为只有当线程运行完才会出现结果。

4、使用线程池

线程池,顾名思义就是一个池子里面放了很多的线程,我们用就将线程从里面拿出来,使用完毕就放回去池子中。设计和数据库连接池相似,存在静态工厂方法用于创建各种线程池。

操作步骤:

1)使用Executors工具类中的静态工厂方法用于创建线程池 newFixedThreadPool:创建可重用且固定线程数的线程池, newScheduledThreadPool:创建一个可延迟执行或定期执行的线程池 newCachedThreadPool:创建可缓存的线程池

2)使用execute方法启动线程

3)使用shutdown方法等待提交的任务执行完成并后关闭线程。

代码演示如下:

public class Demo4 {public static void main(String[] args) {Executor executor = Executors.newFixedThreadPool(5);executor.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}});((ExecutorService) executor).shutdown();}
}

5、Spring实现多线程

在Spring3之后,Spring引入了对多线程的支持,如果你使用的版本在3.1以前,应该还是需要通过传统的方式来实现多线程的。从Spring3同时也是新增了Java的配置方式,而且Java配置方式也逐渐成为主流的Spring的配置方式。

代码演示如下:

导入的包:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.1.0.RELEASE</version></dependency>
</dependencies>

配置类:

@Configuration
@ComponentScan("cn.wolfcode")
@EnableAsync //允许使用异步任务
public class SpringConfig {}

服务类:

@Service
public class SpringService {@Async // 这里进行标注为异步任务,在执行此方法的时候,会单独开启线程来执行public void dowork1() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-->" + i);}}@Asyncpublic void dowork2() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-->" + i);}}
}

测试类:

public class SpringThreadDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);SpringService bean = context.getBean(SpringService.class);bean.dowork1();bean.dowork2();}
}

注意:此时会出现一个DEBUG信息

在这里DEBUG信息不是什么错误,不会影响代码的正常运行,其实可以不用管的,但是为什么出现这个问题呢?

Spring的定时任务调度器会通过BeanFactory.getBean的方法来尝试获取一个注册过的TaskExecutor对象来做任务调度,获取不到TaskExecutor对象再尝试找ScheduledExecutorService 对象,都找不到就报DEBUG信息。报错之后就找自己本身默认的scheduler定时器对象,这个举动其实是做一个提醒作用,所以如果没有强迫症可以不用管它。

解决Spring使用多线程的报错信息

强迫症患者想要解决怎么办,三种方式:

  • 在log4j文件中加入log4j.logger.org.springframework.scheduling = INFO(治标不治本)
  • 在本配置文件或者配置类中设置一个bean
  • 配置类实现AsyncConfigurer接口并覆盖其getAsyncExecutor方法

6 定时器

严格来说定时器(Timer)不是线程,他只是调度线程的一种工具,它里面封装了一个线程,所以我们可以使用定时器来使用线程。

操作步骤:

1)创建Timer 对象

2)调用schedule方法

3)传入TimerTask子类对象

代码演示如下:

Timer timer = new Timer();
timer.schedule(new TimerTask() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-->" + i);}}
}, 100, 100);

​文源网络,仅供学习之用,如有侵权,联系删除。

我整理了一套学习资料,涵盖Java虚拟机、spring框架、Java线程、数据结构、设计模式等等,免费提供给热爱Java的同学! 戳我主页查看获取方式。

command对象提供的3个execute方法是_并发面试题:java中有几种方法可以实现一个线程?...相关推荐

  1. Java中有几种方法可以实现一个线程??用什么关键字修饰同步方法??stop()和suspend()方法为什么不推荐使用??

    1. Java中有几种方法可以实现一个线程?? 两种,分别是继承thread类和实现Runnable类接口. 第一种: new Thread(){}.start();这表示调用Thread子类对象的r ...

  2. java 中有几种方法可以实现一个线程?用什么关键字修饰同步方法 ? stop() 和 suspend() 方 法为何不推荐使用?

    60 . java 中有几种方法可以实现一个线程?用什么关键字修饰同步方法 ? stop() 和 suspend() 方 法为何不推荐使用? 答: 有两种实现方法,分别是继承 Thread类与实现Ru ...

  3. command对象提供的3个execute方法是_前阿里P9的Java面试重点3:多线程

    1. 并行和并发有什么区别? 并行:多个处理器或多核处理器同时处理多个任务. 并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行. 如下图: 并发 = ...

  4. command对象提供的3个execute方法是_Python:3分钟看懂,基于 Psycopg2 的 PostgreSQL 操作指南!

    本Python PostgreSQL教程演示了如何使用PostgreSQL数据库服务器开发Python数据库应用程序.在Python中,我们有用于连接和使用PostgreSQL的serval模块.以下 ...

  5. command对象提供的3个execute方法是_21个极大提高开发效率的VS Code快捷键

    摘要: 高效使用VS Code! 作者:前端小智 原文:21 个VSCode 快捷键,让代码更快,更有趣 Fundebug经授权转载,版权归原作者所有. 注意:自己尝试的时候,Mac(17, pro) ...

  6. java中如何改方法签名_我们可以在Java重写中更改方法签名吗?

    不,在覆盖超类的方法时,我们需要确保两个方法都具有相同的名称,相同的参数和相同的返回类型,否则它们将被视为不同的方法. 简而言之,如果我们更改签名,则尝试执行超类的方法时,将无法覆盖超类的方法. 原因 ...

  7. java 方法 示例_带有示例的Java EnumSetSupplementOf()方法

    java 方法 示例 EnumSet类complementOf()方法 (EnumSet Class complementOf() method) complementOf() method is a ...

  8. sheet中没有getcolumns()方法吗_家庭亲子教育中的八种方法,你做到了吗?

    家庭教育对一个孩子的成长发育是至关重要的,家庭教育才是孩子的启蒙教育,父母是孩子们最好的老师. 1. 给孩子一个选择 允许孩子按照他们自己的兴趣去做事是非常重要的,这是帮助他们成功的最佳途径之一.如果 ...

  9. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?

    答: 1.有两种实现方法,分别是继承Thread类与实现Runnable接口 继承扩展性不强,java总只支持单继承,如果一个类继承Thread就不能继承其他的类了. 2.用synchronized关 ...

最新文章

  1. 拿到2021年灰飞烟灭的算法岗offer的大佬们,简历上都有什么?
  2. MOSS 2010:Visual Studio 2010开发体验(26)——工作流开发概述
  3. SAP Hybris recipe 为 cx 的安装和初始化
  4. Python 黑帽子第二章运行截图
  5. JS module的导出和导入
  6. pycharm-设快捷代码热键
  7. 诗与远方:无题(三十三)
  8. c++输出的值精确到小数点后5位_c/c++linux 2019最新阿里研发类面试题及答案分享...
  9. js在ie追加html,ie下动态加态js文件的方法
  10. create-react-app创建的项目npm run build之后静态文件找不到
  11. [转载] [Python] np.ones_like(ndarray)和np.zeros_like(ndarray)
  12. C++算法学习(力扣:面试题 16.04. 井字游戏)
  13. 计算机考试准考证怎么下载
  14. clark变换第三行系数的由来
  15. 大批制造企业总部离沪 三四线城市成避风港
  16. Go dep init失败
  17. 绝对经典!百句浓缩版小常识(ZT)
  18. 2022江苏最新八大员之(安全员)模拟考试试题及答案
  19. 近红外PbSAg2S量子点(齐岳生物)
  20. #2708. 黑暗(dark)

热门文章

  1. Docker运行GUI软件的方法
  2. hive 中窗口函数row_number,rank,dense_ran,ntile分析函数的用法
  3. spring mvc拦截器HandlerInterceptor
  4. Android 常用权限
  5. OpenGL Shader基本概念
  6. wxpy 0.1.2微信机器人 / 优雅的微信个人号API
  7. JavaScript 设计模式之构造函数模式
  8. 我和《Visual c++2013入门经典(第7版)》的那些事
  9. Java关键字final使用详解
  10. ObserveIT Client安装后屏幕延迟问题