前言


线程,英文Thread。在java中,创建线程的方式有三种:

1、Thread

2、Runnable

3、Callable

在详细介绍下这几种方式之前,我们先来看下Thread类和Runnable接口。

Runnable接口

接口中只有一个run()方法,等待实现类去实现。


  1. package java.lang;
  2. @FunctionalInterface
  3. public interface Runnable {
  4. public abstract void run();
  5. }

Thread类

该类实现了Runnable接口,也提供了很多其他的方法,如yield(),join()等


  1. package java.lang;
  2. public
  3. class Thread implements Runnable {
  4. //获取当前线程
  5. public static native Thread currentThread();
  6. public static native void yield();
  7. //一系列的构造函数
  8. public Thread(Runnable target, String name) {
  9. init(null, target, name, 0);
  10. }
  11. public Thread(ThreadGroup group, String name) {
  12. init(group, null, name, 0);
  13. }
  14. /*调用该方法时,jvm会调用run方法
  15. *Causes this thread to begin execution; the Java Virtual Machine
  16. * calls the run method of this thread.
  17. */
  18. public synchronized void start() {
  19. if (threadStatus != 0)
  20. throw new IllegalThreadStateException();
  21. group.add(this);
  22. boolean started = false;
  23. try {
  24. start0();
  25. started = true;
  26. } finally {
  27. try {
  28. if (!started) {
  29. group.threadStartFailed(this);
  30. }
  31. } catch (Throwable ignore) {
  32. }
  33. }
  34. }
  35. }

一、实现Runnable接口


  1. public class i_Runnable {
  2. /**
  3. * 主线程main方法
  4. * @param args
  5. */
  6. public static void main(String[] args) {
  7. for (int i = 0; i < 100; i++) {
  8. System.out.println(Thread.currentThread().getName() + "====" + i);
  9. if (i == 20) {
  10. RunnableThreadTest rtt = new RunnableThreadTest();
  11. //子线程
  12. new Thread(rtt, "new Thread[1]====").start();
  13. //new Thread(rtt, "新线程2").start();
  14. }
  15. }
  16. }
  17. /**
  18. * RunnableThreadTest实现Runnable接口
  19. * @author YANG
  20. *
  21. */
  22. static class RunnableThreadTest implements Runnable {
  23. private int i;
  24. @Override
  25. public void run() {
  26. for (i = 0; i < 100; i++) {
  27. System.out.println(Thread.currentThread().getName() + " " + i);
  28. }
  29. }
  30. }
  31. }

执行结果:

注意:

** 执行结果只截取了部分内容。

** 如果RunnableThreadTest类前不加static,会报错No enclosing instance of type i_Runnable is accessible. Must qualify the allocation with
an enclosin。因为只有内部类修饰为静态时,才可以在静态类方法(main方法)中调用该类的成员变量和方法。

二、继承Thread类


  1. public class a_Thread {
  2. public static void main(String[] args) {
  3. Runner1 r=new Runner1();
  4. r.start(); //已经有thread 不需要new,直接调用start即可。
  5. for (int i = 0; i < 100; i++) {
  6. System.out.println("main Thread:"+i);
  7. }
  8. }
  9. //Runner1继承Thread类,重写run方法
  10. static class Runner1 extends Thread{
  11. @Override
  12. public void run() {
  13. for (int i = 0; i < 100; i++) {
  14. System.out.println("Runner1:"+i);
  15. }
  16. }
  17. }
  18. }

思考:能不能将上面的r.start(); 改为 r.run();

分析:换成run()方法之后,就变成了普通的方法调用,只有一个主线程,没有子线程。

执行结果:为了方便显示,我们将循环次数改为10。


  1. Runner1:0
  2. Runner1:1
  3. Runner1:2
  4. Runner1:3
  5. Runner1:4
  6. Runner1:5
  7. Runner1:6
  8. Runner1:7
  9. Runner1:8
  10. Runner1:9
  11. main Thread:0
  12. main Thread:1
  13. main Thread:2
  14. main Thread:3
  15. main Thread:4
  16. main Thread:5
  17. main Thread:6
  18. main Thread:7
  19. main Thread:8
  20. main Thread:9

三、实现Callable接口

前面两种方式是传统的线程技术中的内容,第三种方式Callable和Future是jdk1.5之后新增的。我们先来补充点东西,看看这种方式与之前的方式有什么联系。


  1. //实现Callable接口
  2. public class j_CallableTest implements Callable<String> {
  3. public static void main(String[] args) {
  4. j_CallableTest test=new j_CallableTest();
  5. FutureTask<String> ft=new FutureTask<>(test);
  6. for (int i = 0; i < 100; i++) {
  7. System.out.println(Thread.currentThread().getName()+" i的值为="+i);
  8. if(i==20){
  9. new Thread(ft,"子线程").start();
  10. }
  11. }
  12. }
  13. //重写call方法
  14. @Override
  15. public String call() throws Exception {
  16. int i = 0;
  17. String reString = "";
  18. for (; i < 100; i++) {
  19. reString = Thread.currentThread().getName() + " " + i;
  20. System.out.println(reString);
  21. }
  22. return reString;
  23. }
  24. }

从上面可以看到,new Thread的方式还是用的public Thread(Runnable target, String name); 说明FutureTask也是Runnable类型的,他们之间的关系可以从下图中看出来。

那么,使用Callable和Future的方式有什么特点呢?

我们从他们的定义来看,Callable接口中只有一个方法,返回值为V。前两种方式都是返回void。


  1. @FunctionalInterface
  2. public interface Callable<V> {
  3. /**
  4. * Computes a result, or throws an exception if unable to do so.
  5. *
  6. * @return computed result
  7. * @throws Exception if unable to compute a result
  8. */
  9. V call() throws Exception;
  10. }

小结:

1、接口实现更灵活,java不支持多继承。在这方面,Runnable和Callable更有优势。

2、返回值问题。Runnable和Thread都不能有返回值,但Callable可以,而且支持多种类型的数据。

就这两点来看,新增的Callable和Future的实现方式优势十分明显啊。但是追到原理,其实这三种都可以归结为一种方式。

java线程——三种创建线程的方式的更多相关文章

  1. 【Java 线程的深入研究1】Java 提供了三种创建线程的方法

    Java 提供了三种创建线程的方法: 通过实现 Runnable 接口: 通过继承 Thread 类本身: 通过 Callable 和 Future 创建线程. 1.通过实现 Runnable 接口来 ...

  2. JavaScript DOM三种创建元素的方式

    三种创建元素的方式: document.write() element.innerHTML document.createElement() 初始HTML内容: <button>btn&l ...

  3. java线程(1)——三种创建线程的方式

    前言 线程,英文Thread.在java中,创建线程的方式有三种: 1.Thread 2.Runnable 3.Callable 在详细介绍下这几种方式之前,我们先来看下Thread类和Runnabl ...

  4. Java多线程学习总结--线程概述及创建线程的方式(1)

    在Java开发中,多线程是很常用的,用得好的话,可以提高程序的性能. 首先先来看一下线程和进程的区别: 1,一个应用程序就是一个进程,一个进程中有一个或多个线程.一个进程至少要有一个主线程.线程可以看 ...

  5. 线程系列1--Java创建线程的几种方式及源码分析

    线程--创建线程的几种方式及源码分析 开始整理下线程的知识,感觉这块一直是盲区,工作中这些东西一直没有实际使用过,感觉也只是停留在初步的认识.前段时间一个内推的面试被问到,感觉一脸懵逼.面试官说,我的 ...

  6. Servlet三种创建方式

    直接实现 Servlet 接口不太方便,所以 Servlet 又内置了两个 Servlet 接口的实现类(抽象类),分别为 GenericServlet 和 HttpServlet,因此,创建 Ser ...

  7. Django多对多表的三种创建方式,MTV与MVC概念

    MTV与MVC MTV模型(django): M:模型层(models.py) T:templates V:views MVC模型: M:模型层(models.py) V:视图层(views.py) ...

  8. Django-多对多关系的三种创建方式-forms组件使用-cookie与session-08

    目录 表模型类多对多关系的三种创建方式 django forms 组件 登录功能手写推理过程 整段代码可以放过来 forms 组件使用 forms 后端定义规则并校验结果 forms 前端渲染标签组件 ...

  9. Js基础知识4-函数的三种创建、四种调用(及关于new function()的解释)

    在js中,函数本身属于对象的一种,因此可以定义.赋值,作为对象的属性或者成为其他函数的参数.函数名只是函数这个对象类的引用. 函数定义 // 函数的三种创建方法(定义方式) function one( ...

随机推荐

  1. Reference Counting GC (Part one)

    目录 引用计数法 计数器值的增减 new_obj()和update_ptr()函数 new_obj()生成对象 update_ptr()更新指针ptr,对计数器进行增减 优点 可即可回收垃圾 最大暂停 ...

  2. yum配置中driver-class-name: com.mysql.jdbc.Driver报错

    错误: 原因: 解决方法:把方框中的<scope>runtime</scope>删掉

  3. CentOS yum安装mcrypt详细图解教程

    CentOS yum安装mcrypt详细图解教程 在Linux的发行版CentOS 6.3 系统下,LAMP(Linux+Apache+Mysql+php)环境搭建好后发现PHPMyadmin提示 “ ...

  4. WP8 学习笔记(001_环境配置)

    Step 1  WP8 的开发要求64位操作系统,Windows 8及以上版本,需要激活版,建议网上买一个注册码.详见安装双系统. Step 2 安装好系统并已经激活之后,需要安装Windows Ph ...

  5. .netcore2.1开发部署及在centos7.x下的部署

    .netcore2.1的优势毋容置疑,具体的性能建议去实际test对比,相对于之前的.netfx不知道快了多少.选择C#作为后端开发语言,主要基于以下三点: 1)代码优雅 : 2)快速搭建一套小型企业 ...

  6. [Python] Understand List Comprehensions in Python

    List comprehensions provide a concise way to create new lists, where each item is the result of an o ...

  7. 转:mac环境下使用svn

    在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境.在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还 ...

  8. Spring MVC原理及实例基础扫盲篇

    近期 项目中刚接触了SpringMVC,就把这几天看的跟实践的东西写出来吧. 一.首先,先来了解一下SpringMVC究竟是个什么样的框架? Spring Web MVC是一种基于Java的实现了We ...

  9. 一些安全的DNS提供商

    检测当前使用的DNS服务器    https://dnsleaktest.com 一些安全的DNS提供商 DNS提供商名称 主DNS服务器 次要DNS服务器 Google 8.8.8.8 8.8.4. ...

  10. rtsp和sdp协议简介

    RTSP是由Real network 和Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议. 实时流协议(RTSP)建立并控制一个或几个时间同步的连续流媒体,如音频和视频.尽管 ...