三种方式创建:  

  1. 通过继承Thread类来创建并启动多线程的方式

  2. 通过实现Runnable接口来创建并启动线程的方式

  3. 通过实现Callable接口来创建并启动线程的方式

  4. 总结Java中创建线程的方式,比较各自优势和区别

一、继承Thread类创建线程类

  java使用Thread类表示线程,所有的线程对象都必须是Thread类或者其子类的实例,每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java中通过继承Thread类来创建并启动多线程的步骤如下:

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务

   因此把run()方法称为线程执行体

  2. 创建Thread子类的实例,即创建了线程对象

  3. 调用线程对象的start()方法来启动该线程

代码实例:

//继承Thread类创建线程
public class ThreadCreat extends Thread{//线程执行方法
    @Overridepublic void run() {for (int i = 0; i < 2; i++) {       //获取当前线程名可以用thisSystem.out.println(this.getName());}}public static void main(String[] args) {for (int i = 0; i < 2; i++) {System.out.println("这里是主线程"+Thread.currentThread().getName());if(i==1){//创建一个线程new ThreadCreat().start();//创建第二个线程new ThreadCreat().start();}}}
}

运行结果:

  第一次运行结果:                                                                   第二次运行结果:

    这里是主线程main                  这里是主线程main

       这里是主线程main                  这里是主线程main

    Thread-0                      Thread-0
    Thread-1                      Thread-0
    Thread-1                      Thread-1
    Thread-0                      Thread-1

该程序无论被执行多少次输出的记录数是一定的,一共是6条记录。主线程会执行for循环打印2条记录,两个子线程分别打印2条记录,一共6条记录。因为i变量是ThreadCreat的实例属性,而不是局部变量,但因为程序每次创建线程对象时都需要创建一个ThreadCreat对象,所以Thread-0和Thread-1不能共享该实例属性,所以每个线程都将执行2次循环。

二、实现Runnable接口

  1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体

  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象

  3. 调用线程对象的start()方法来启动线程

  Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法

代码实例:   

//实现Runnable接口创建线程
public class ThreadCreat implements Runnable{

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

 

  第一次执行结果:                                         

main,0                                                                          main,0

main,1                      main,1
新线程-1,0                   新线程-1,0
新线程-1,1                   新线程-1,1

新线程-2,0

从该运行结果中我们可以看出,控制台上输出的内容是乱序的,而且每次结果不尽相同。这是因为:
  1. 在这种方式下,程序所创建的Runnable对象只是线程的target,而多个线程可以共享同一个target。

  2. 所以多个线程可以共享同一个线程类即线程的target类的实例属性。

  3. 往控制台窗口print()输出的过程并不是多线程安全的,在一个线程输出过程中另一个线程也可以输出。

 

实现Runnable接口比继承Thread类所具有的优势:

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

三、使用Callable和Future创建线程

从Java 5开始,Java提供了Callable接口,该接口怎么看都像是Runnable接口的增强版,Callable接口提供了一个call()方法可以作为线程执行体,但call()方法比run()方法功能更强大

call方法和run方法的区别:

  1. call()方法可以有返回值,run方法没有。

  2. call()方法可以声明抛出异常,run方法没有

call()方法还有一 个返回值-----call()方法并不是直接调用,它是作为线程执行体被调用的。那么如何获取call()方法的返回值呢?

 Future接口概述

Java 5提供了Future接口来代表Callable接口里call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口和Runnable接口可以作为Thread类的target。在Future接口里定义了如下几个公共方法来控制它关联的Callable任务:

  1. boolcan cancel(boolean maylnterruptltRunning):试图取消该Future里关联的Callable任务

  2. V get():返回Callable任务里call()方法的返回值。调用该方法将导致程序阻塞,必须等到子线程结束后才会得到返回值

  3. V get(long timeout,TimeUnit unit):返回Callable任务里call()方法的返回值。

该方法让程序最多阻塞timeout和unit指定的时间,如果经过指定时间后Callable任务依然没有返回值,

将会抛出TimeoutExccption异常

  4. boolean isCancelled():如果在Callable任务正常完成前被取消,则返回true

  5. boolean isDone():妇果Callable任务已完成,则返回true

注意:Callable接口有泛型限制,Callable接口里的泛型形参类型与call()方法返回值类型相同。

 创建并启动有返回值的线程的步骤

1. 创建Callable接口的实现类,并实现call()方法,该cal()方法将作为线程执行体,且该call()方法有返回值

2. 创建Callable实现类的实例,使用FutureTask类来包装Callable对象

该FutureTask对象封装了该Callable对象的call()方法的返回值

3. 使用FutureTask对象作为Thread对象的target创建并启动新线程

4. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

 代码实例:

public class MyCallableTest implements Callable<Integer>{// 实现call方法,作为线程执行体public Integer call(){int i = 0;for ( ; i < 100 ; i++ ){System.out.println(Thread.currentThread().getName()+ "\t" + i);}// call()方法可以有返回值return i;}public static void main(String[] args) {// 创建Callable对象MyCallableTest myCallableTest = new MyCallableTest();// 使用FutureTask来包装Callable对象FutureTask<Integer> task = new FutureTask<Integer>(myCallableTest);for (int i = 0 ; i < 100 ; i++){System.out.println(Thread.currentThread().getName()+ " \t" + i);if (i == 20){// 实质还是以Callable对象来创建、并启动线程new Thread(task , "callable").start();}}try{// 获取线程返回值System.out.println("callable返回值:" + task.get());}catch (Exception ex){ex.printStackTrace();}}
}

运行上面程序,将看到主线程和call()方法所代表的线程交替执行的情形,程序最后还会输出call()方法的返回值。上面程序中创建Callable实现类与创建Runnable实现类并没有太大的差别,只是Callable的call()方法允许声明抛出异常, 而且允许带返回值。当主线程中当循环变量i等于20时,程序启动以FutureTask对象为target的线程。程序最后调用FutureTask对象 的get()方法来返回call()方法的返回值——该方法将导致主线程阻塞,直到call()方法结束并返回为止。

原文链接http://www.cnblogs.com/sunddenly/p/4399061.html

转载于:https://www.cnblogs.com/xing-12/p/9048109.html

回炉再造-多线程的创建相关推荐

  1. 回炉再造-多线程和进程的对比

    进程和线程区别总结: 操作系统可以同时执行多个任务,每个任务就是进程:进程可以同时执行多个任务,每个任务就是线程.简而言之,一个程序运行后至少有一个进程,一个进程里可以包含多个线程,但至少要包含一个线 ...

  2. 回炉再造-多线程生命周期

    五种状态:新建(New).就绪(Runnable).运行(Running).阻塞(Blocked)和死亡(Dead)5种状态. 1. 新建状态,当程序使用new关键字创建了一个线程之后,该线程就处于新 ...

  3. Java回炉之多线程(一)

    Java回炉之多线程(一) Java回炉之多线程一 创建方法 设置获取线程名 获取当前线程 优先级 线程控制 生命周期 状态转换 同步代码块 同步方法 Lock锁 等待唤醒机制 线程组 线程池 定时器 ...

  4. 回炉再造,灵活的YMenuView2.0诞生

    出处: 炎之铠邮箱:yanzhikai_yjk@qq.com 博客地址:http://blog.csdn.net/totond 本文原创,转载请注明本出处! 本项目GitHub地址:https://g ...

  5. Win32 多线程的创建方法,区别和联系

    2019独角兽企业重金招聘Python工程师标准>>> Win32多线程的创建方法主要有: CreateThread() _beginthread()&&_begin ...

  6. java线程的创建与执行_Java多线程的创建和运行

    1.多线程的好处 多线程是一个很有用的东西,它使的系统可以同时运行多个任务,提高程序的执行效率.大家平时可能没有注意到,其实我们电脑能同时执行多个程序的基本原理就是多线程. 每一个程序都是一个进程,而 ...

  7. c++:多线程的创建和unique_lock<mutex>的使用

    1.多线程的创建 1)包括头文件 #include<thread> #include<mutex> 2)新建线程 新建线程两个 使用thread 线程名来新建一个线程 并在线程 ...

  8. MFC多线程的创建,包括工作线程和用户界面线程

    MFC多线程的创建 1.MFC多线程简介 MFC对多线程进行了一层简单的封装,在Visual C++中每个线程都是从CWinThread类继承而来的.每一个应用程序的执行都有一个主线程,这个主线程也是 ...

  9. java中多线程的创建方式一:

    //多线程的创建: //方式一:继承于Thread类的方式进行创建 //1.创建一个继承Thread类的子类 //2.重写Thread类中的run()方法–>将此线程执行的操作写在run方法中 ...

最新文章

  1. switch case
  2. 开源监控软件-Nagios-Rhel5.9安装手册
  3. SharePoint 2013 开发——SharePoint Designer 2013工作流
  4. python条件表达式有哪几个_python条件表达式:多项分支,双向分支
  5. 图解TC++3.0开发教程
  6. WPF converter(包含传递复杂参数)
  7. android电话系统,Android电话系统之-rild.doc
  8. python绘制汉字_OpenCV Python 绘制中文字
  9. Redis基础(六)——事务
  10. Shell中$X的含义
  11. 突然发现Windows 7 Ultimate中有个BUG,分享一下哈!
  12. Atitit.redis操作总结
  13. 小红帽系统进入oracle,11G RAC 安装在红帽6上,grid跑root.sh报错
  14. Java中的重载(overloading)和重写(overriding)
  15. Android开发布局 案例二
  16. 中国气象数据网的.nc数据批量下载(Python代码)
  17. 废品回收小程序、APP UNIAPP开发带有用户端和回收员端
  18. 重庆财经职业学院计算机一级考试题,2021年重庆财经职业学院单招语文考试模拟试题库...
  19. VM虚拟机分区硬盘/安装win10系统
  20. VSCode选择远程服务器的虚拟环境

热门文章

  1. 珠心算测验(爆炸型)
  2. [tensorflow]联邦学习框架TFF安装记录(基于docker)
  3. CodeVS1373 射命丸文【矩阵前缀和】
  4. 虚拟化技术之 VMware Workstation教程(一)
  5. Android之TextView设置autoLink属性后自定义跳转到指定界面
  6. 微信群如何裂变怎么让微信群裂变拉人
  7. 笔记:阿里云服务器下python 配置邮箱服务
  8. 0905 RTCP RR SDES 包文介绍
  9. 山洪地质灾害监测预警
  10. windows10企业版安装西门子博途V15---03安装仿真软件