上一篇我们初步认识了线程,现在我们来讲一下,创建线程的三种方式

1.继承Thread

类通过继承thread类,然后重写run方法(run方法中是线程真正执行的代码,runable也是如此)即可。当子类被实例化后,调用start方法即可启动线程。(不能调用run方法,直接调用run方法,和方法调用没有区别,不是线程。)

这种继承thread创建线程的方式,线程之间无法共享实例变量,因为每次都创建了新的实例,肯定不能共享了。

/*** 通过集成Thread类,重写run方法启动线程*/
public class FirstThread extends Thread {private int i;public void run() {for (; i < 100; i++) {//当线程类继承thread类时,直接使用this即可获得当前线程//Thread对象的getName(),返回当前线程的名字//因此可以直接调用getName()方法返回当前线程的名字System.out.println(Thread.currentThread().getName() + " " + i);}}public static void main(String[] args) {for (int i = 0; i < 100; i++) {//调用thread的currentThread()方法获取当前线程System.out.println(Thread.currentThread().getName() + " " + i);if(i==20){//创建并启动第一个线程new FirstThread().start();//创建并启动第二个线程new FirstThread().start();//类似Runable的启动方法,通过继承thread也可以。FirstThread firstThread1 = new FirstThread();new Thread(firstThread1,"thread线程").start();}}}
}

执行效果大致如下:

有四个线程启动,一个主线程,线程名字为main 0。还有三个其他线程,线程名分别为:Thread-0、Thread-1、thread线程。这四个线程都打印了1到100。运行结果的一部分展示如下:

2.实现Runable接口

顾名思义,我们需要创建一个类,由此类实现runable接口,然后重写run方法。在启动线程时,将类实例化,然后创建thread,然后将实例化得对象作为创建thread的的参数即可。这种方式创建的线程类,是互相共享资源的。

/*** 通过实现runable接口来创建线程类*/
public class SecondThread implements Runnable {private int i;//run方法同样是线程执行体public void run() {for (; i < 100; i++) {//当线程类实现runable接口时//如果想获取当前线程,只能用Thread.currentThread()方法System.out.println(Thread.currentThread().getName() + " " + i);}}public static void main(String[] args) {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + " " + i);if (i==20){SecondThread st = new SecondThread(); ////通过new Thread(Target,name)方法创建新线程new Thread(st,"新线程1").start();new Thread(st,"新线程2").start();}}}
}

通过runable来创建线程是共享实例变量的,故执行结果是i是被共享的,不是新线程1和新线程2 各自执行打印1到100,而是拿到上一线程修改后的变量,继续打印。执行部分效果如下:

其实类似的还有一种创建方式,是通过lambda表达式进行创建的了,原理是和实现runable接口是一样的。

public class T02_CreateThreadByLambda {public static void main(String[] args) {for (int i = 0; i < 100; i++) {if (i == 20) {for (int j = 0; j < 100; j++) {new Thread(() -> {System.out.println("Hello Lambda!");}).start();}}}}
}

执行的部分结果如下:由图可知,我们这种创建方式也是可以,其实lambda表达式,就相当于创建thread的参数,然后启动线程。

3.使用Callable和Future创建线程

从继承Thread类和实现Runnable接口可以看出,上述两种方法都不能有返回值,且不能声明抛出异常。而Callable接口则实现了此两点,Callable接口如同Runable接口的升级版,其提供的call()方法将作为线程的执行体,同时允许有返回值。

但是Callable对象不能直接作为Thread对象的参数,因为Callable接口是 Java 5 新增的接口,不是Runnable接口的子接口。对于这个问题的解决方案,就引入 Future接口,此接口可以接受call() 的返回值,RunnableFuture接口是Future接口和Runnable接口的子接口,可以作为Thread对象的target 。并且, Future 接口提供了一个实现类:FutureTask 。

FutureTask实现了RunnableFuture接口,可以作为 Thread对象的target。


/*** 使用callable和future创建线程*/
public class ThirdThread {public static void main(String[] args) {//创建Callable对象ThirdThread rt = new ThirdThread();//先使用Lambda表达式创建Callable<Interger>对象//使用furureTask来 包装Callable对象FutureTask<Integer> task = new FutureTask<>((Callable<Integer>) () -> {int i = 0;for (; i < 100; i++) {System.out.println(Thread.currentThread().getName() + " " + i);}//call方法可以有返回值return i;});for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + " " + i);if (i == 20) {//实质还是以callable对象来创建并启动线程的new Thread(task, "有返回值的线程").start();}}try {//获取线程返回值System.out.println("子进程的返回值:" + task.get());}catch (Exception ex){ex.printStackTrace();}}
}

执行结果我们我们可以猜测一下,应该是有名称叫“main”线程打印0到99,名称叫“有返回值的线程”打印0到99,最后是子进程,由于最后还进行了一次++,所以返回值为100,所以就打印了一次:“子进程的返回值:100”

执行的部分结果如下:

中间都是打印“有返回值的线程:i”  ,我省略掉了。

4.使用线程池创建

1)使用Executors类中的newFixedThreadPool(int num)方法创建一个线程数量为num的线程池

2)调用线程池中的execute()方法执行由实现Runnable接口创建的线程;调用submit()方法执行由实现Callable接口创建的线程

3)调用线程池中的shutdown()方法关闭线程池

public class Thread4 {public static void main(String[] args) throws Exception {Thread.currentThread().setName("主线程");System.out.println(Thread.currentThread().getName()+":"+"输出的结果");//通过线程池工厂创建线程数量为2的线程池ExecutorService service = Executors.newFixedThreadPool(2);//执行线程,execute()适用于实现Runnable接口创建的线程service.execute(new ThreadDemo4());service.execute(new ThreadDemo6());service.execute(new ThreadDemo7());//submit()适用于实现Callable接口创建的线程Future<String> task = service.submit(new ThreadDemo5());//获取call()方法的返回值String result = task.get();System.out.println(result);//关闭线程池service.shutdown();}
}
//实现Runnable接口
class ThreadDemo4 implements Runnable{@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+"输出的结果");}}
//实现Callable接口
class ThreadDemo5 implements Callable<String>{@Overridepublic String call() throws Exception {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+"输出的结果");return Thread.currentThread().getName()+":"+"返回的结果";}}
//实现Runnable接口
class ThreadDemo6 implements Runnable{@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+"输出的结果");}}
//实现Runnable接口
class ThreadDemo7 implements Runnable{@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+"输出的结果");}}

输出结果如下:

【并发编程】创建线程的四种方式相关推荐

  1. Java 并发 多线程:创建线程的四种方式

    Java 并发 多线程: 创建线程的四种方式 继承 Thread 类并重写 run 方法 实现 Runnable 接口 实现 Callable 接口 使用线程池的方式创建 1. 通过继承 Thread ...

  2. 创建线程的四种方式(Thread、Runnable、线程池、Callable)

    目录 一.直接继承Thread类,然后重写run方法 二.实现Runnable接口 三.线程池创建 四.实现Callable接口 创建线程有四种方式:1.继承Thread类   2.实现Runnabl ...

  3. java并发编程基础系列(五): 创建线程的四种方式

    线程的创建一共有四种方式: 继承于Thread类,重写run()方法: 实现Runable接口,实现里面的run()方法: 使用 FutureTask 实现有返回结果的线程 使用ExecutorSer ...

  4. java中创建线程的四种方式及线程池详解

    众所周知,我们在创建线程时有四种方法可以用,分别是: 1.继承Thread类创建线程 2.实现Runnable接口创建线程 3.使用Callable和Future创建线程 4.使用线程池创建(使用ja ...

  5. 【Java并发编程】并发模拟的四种方式

    文章目录 并发模拟的四种方式 一.Postman 二.Apache Bench(AB) 三.并发模拟工具JMeter 四.代码模拟 并发模拟的四种方式 一.Postman Postman是一个款htt ...

  6. JUC多线程:创建线程的四种方式

    在 Java 中,实现多线程的主要有以下四种: (1)继承 Thread 类,重写 run() 方法: (2)实现 Runnable 接口,实现 run() 方法,并将 Runnable 实现类的实例 ...

  7. 学习笔记(23):Python网络编程并发编程-开启线程的两种方式

    立即学习:https://edu.csdn.net/course/play/24458/296437?utm_source=blogtoedu 开启线程的两种方法:threading.Thread 1 ...

  8. java创建线程的四种方式

    目录 1.直接初始化Thead类,实现Runnable接口 2.继承Thread类 3.实现callable接口 4.使用线程池创建线程 1.直接初始化Thead类,实现Runnable接口 查看Th ...

  9. 创建现成的四种方式 多线程与并发的基本概念:

    多线程与并发的基本概念: 多线程 一:什么是线程? 进程:进行中应用程序 线程:是进程组成者,一个进程中可能包含多个线程 cpu执行程序的最小单位是线程,cpu在同一时间内只能执行一个线程,在多个线程 ...

最新文章

  1. 服务器BMC、BIOS、IPMI、UEFI技术解析
  2. zabbix工作流程(自定义添加监控项目)
  3. 《卓有成效的程序员》----读书笔记一
  4. hdu 2897(威佐夫博奕变形)
  5. python爬虫反爬对抗_python爬虫反反爬,你几乎可以横扫大部分 css 字体加密的网站...
  6. 实现Linux系统外部和容器内部的文件传输
  7. 大数据与大量数据处理_我们如何处理和使用如此大量的数据?
  8. android adb工具linux,Ubuntu Android ADB 使用
  9. Git HTTP方式克隆远程仓库到本地
  10. 2016.08.30~2017.07.20
  11. 总结div里面水平垂直居中的实现方法
  12. 机器视觉:USB 3.0知识答疑
  13. 知识蒸馏综述:代码整理
  14. Android 加密
  15. 模拟多线程给多用户发送短信
  16. oracle 应收 系统选项,Oracle财务系统应收账款模块操作手册
  17. 程序员笔名、别名_适合程序员的英文名字
  18. 新浪微博开发者平台应用申请及配置说明
  19. [Windows系统]查看电脑开关机时间
  20. oracle正则表达式匹配字母,oracle正则表达式函数 匹配

热门文章

  1. linux下的几种隐藏技术
  2. editplus配置 linux shell 语法高亮 自动补全
  3. 2018几大主流的 UI/JS 前端框架
  4. pow函数gcc编译提示 undefined reference to `power' 的解决办法
  5. iconv文件编码判断转换
  6. 如何识别高级的验证码
  7. 关于滴水的VT调试器
  8. UNIX中的Poll函数
  9. UNIX进程的创建,进程链和进程扇
  10. CentOS-7.2部署OpenLDAP服务器以及客户端