所有JAVA线程都必须是Thread或其子类的实例。

继承Thread类创建线程

步骤如下,

  • 定义Thead子类并实现run()方法,run()是线程执行体
  • 创建此子类实例对象,即创建了线程对象
  • 调用线程对象的start()方法来启动线程

下面是一个例子,

package threads;

public class FirstThread extends Thread {
//通过继承thread方式实现多线程
//i不会被多个线程共享
private int i;
public void run() {
for(; i<20; i++) {
//System.out.println(Thread.currentThread().getName()+" "+i);
//System.out.println(this.getName()+" "+i);
//if extends Thread, here this==Thread.currentThread()
System.out.println(getName()+" "+i);
}
} public static void main(String[] args) {
for (int i=0; i<50; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20){
new FirstThread().start();
new FirstThread().start();
}
}
}
}

执行结果, 可见thread-5和thread-6的i值都是从0开始,互不影响

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
main 20
Thread-5 0
Thread-5 1
Thread-5 2
Thread-5 3
main 21
Thread-5 4
main 22
Thread-5 5
main 23
Thread-5 6
main 24
Thread-5 7
main 25
Thread-6 0
main 26
Thread-6 1
main 27
Thread-6 2
main 28
Thread-6 3
main 29
Thread-6 4
main 30
Thread-6 5
main 31
Thread-6 6
main 32
Thread-6 7
main 33
Thread-6 8
main 34
main 35
Thread-6 9
main 36
Thread-6 10
main 37
Thread-6 11
main 38
Thread-6 12
main 39
Thread-6 13
main 40
Thread-6 14
main 41
Thread-6 15
main 42
Thread-6 16
main 43
Thread-6 17
main 44
Thread-6 18
main 45
Thread-6 19
main 46
main 47
main 48
main 49
Thread-5 8
Thread-5 9
Thread-5 10
Thread-5 11
Thread-5 12
Thread-5 13
Thread-5 14
Thread-5 15
Thread-5 16
Thread-5 17
Thread-5 18
Thread-5 19

实现Runable接口创建线程类

步骤如下,

  • 定义Runable的实现类,重写run()方法作为线程执行体
  • 创建Runable实现类的实例对象,并将此实例对象作为Thread的targe再创建线程对象,此线程对象才是真正的子线程对象。
  • 调用线程对象的start()方法启动线程

具体例子如下,

package threads;

public class SecondThread implements Runnable {
//i将被多个线程共享
private int i; @Override
public void run() {
// must use Thread.currentThread when implements Runnable
for(; i<20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
} public static void main(String[] args) {
for (int i=0; i<50; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20){
SecondThread st = new SecondThread();
//多个线程共享了同一个target, 将会共享i
new Thread(st, "new thread 1").start();
new Thread(st, "new thread 2").start();
}
}
} }

执行结果, 可以看到子线程 new Thread1和new thread2 的i是连续的,共享了同一个i值

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
main 20
new thread 1 0
new thread 1 1
new thread 1 2
new thread 1 3
main 21
new thread 2 4
main 22
new thread 2 5
new thread 1 4
main 23
new thread 1 7
main 24
new thread 1 8
main 25
new thread 2 6
new thread 1 9
new thread 2 10
new thread 1 11
new thread 2 12
main 26
new thread 2 14
main 27
new thread 2 15
main 28
new thread 1 13
main 29
new thread 1 17
main 30
new thread 1 18
main 31
new thread 1 19
main 32
main 33
main 34
new thread 2 16
main 35
main 36
main 37
main 38
main 39
main 40
main 41
main 42
main 43
main 44
main 45
main 46
main 47
main 48
main 49

使用Callable和Future创建线程

Callable接口

Callable接口特点,与Runable的区别

  • Callable类似于Runable的增强版,区别在于Callable是可以有返回值,并且可以抛出异常的。
  • Callable中有一个call()方法,可以作为线程的执行体,但是线程执行体不会被直接调用,因为无法直接获取子线程返回值,
  • Callable接口不是Runable接口,所以无法作为Thread的target来像Runable那样创建线程

基于以上三点,Future接口派上用场了,

Future接口

Future接口提供了一个FutherTask实现类,此实现类还实现了Runable接口,因此它的实例可以作为Thread类的target,与Callable结合使用从而实现多线程。

Future接口中有如下方法控制线程,

cancel(..)取消关联的Callable任务

get(..)获取关联的Callable钟call()方法的返回值,这里解决了Callable实现多线程但无法直接调用call()获取子线程返回值的问题

get(timeout, unit).

isCancelled()

isDone()

  • 使用Callable和Future创建线程的步骤如下,
  • 创建Callable的实现类,并实现call()方法作为线程执行体
  • 使用FutureTask类来包装Callable对象
  • 使用FutureTask类对象作为Thread的target来创建子线程
  • 调用FutureTask类对象的get()方法获取子线程结束后的返回值,此过程可以抛出异常

下面是一个例子,

package threads;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask; public class ThirdThread {
public static void main(String[] args) {
ThirdThread rt = new ThirdThread();
// FutureTask 是一个包装类,封装Callable对象
FutureTask<Integer> task = new FutureTask<Integer>( new Callable<Integer> () { //call()将作为子线程的执行体
@Override
public Integer call() throws Exception {
int i = 0;
for(; i<20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
} }); for (int i=0; i<100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
if (i == 20) {
new Thread(task, "new thread").start();
}
} try {
System.out.println("Return value from sub thread: "+task.get());
}catch( Exception e) {
e.printStackTrace();
}
}
}

执行结果,

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
main 20
main 21
main 22
main 23
main 24
main 25
new thread 1 0
main 26
new thread 1 1
main 27
new thread 1 2
main 28
new thread 1 3
main 29
new thread 1 4
main 30
new thread 1 5
main 31
new thread 1 6
main 32
new thread 1 7
main 33
new thread 1 8
main 34
new thread 1 9
main 35
new thread 1 10
main 36
new thread 1 11
main 37
new thread 1 12
main 38
new thread 1 13
main 39
new thread 1 14
main 40
new thread 1 15
main 41
new thread 1 16
main 42
new thread 1 17
main 43
new thread 1 18
main 44
new thread 1 19
main 45
main 46
main 47
main 48
main 49
Return value from sub thread: 20

创建线程的三种方式对比

Callable与Runable方式基本相同,区别是Callable有返回值并且可以抛出异常。

Callable与Runable优缺点,

  • 线程类只是实现了Callable和Runable接口,还可以继承别的类,扩展性强,更灵活
  • 多个线程可以共享同一个定义在现成体中的变量,可以方便实现资源共享

缺点是编程比较复杂,且访问当前线程必须要 Thread.currentThread()

采用继承Thread实现多线程的优缺点,

  • 优点是编程简单,且直接使用this就可以访问当前线程
  • 缺点是不够灵活,已经继承了Thread类,就不能继承别的父类。

因此一般使用第三种方式实现多线程。即Callable接口结合Runable接口的方式

JAVA基础知识之多线程——三种实现多线程的方法及区别的更多相关文章

  1. Java基础知识学习(三)

    面向对象部分 首先要了解面向对象的思想,与C#一致,都是面向对象的语言 访问修饰符 public 共有的,对所有类可见. protected 受保护的,对同一包内的类和所有子类可见. private ...

  2. Java基础知识盘点(三)- 线程篇

    创建线程的方式及实现 一.继承Thread类创建线程类 1.定义Thread的子类,并重写run方法,因为该方法的方法体就是代表了线程要完成的任务,因此run方法又叫做执行体. 2.创建Thread子 ...

  3. Java Web开发Tomcat中三种部署项目的方法

    第一种方法:在tomcat中的conf目录中,在server.xml中的,<host/>节点中添加: <Context path="/hello" docBase ...

  4. Java基础知识强化83:System类之gc()方法(垃圾回收)以及和finalize()区别

    1. System概述: System类包含一些有用的类字段和方法.它不能被实例化. 2. gc()方法:垃圾回收器 public static void gc()       调用gc方法暗示着Ja ...

  5. python三种导入模块的方法和区别

    方法一: import modname 模块是指一个可以交互使用,或者从另一Python 程序访问的代码段.只要导入了一个模块,就可以引用它的任何公共的函数.类或属性.模块可以通过这种方法来 使用其它 ...

  6. JAVA基础知识总结:三

    一.Java语句的执行结构 1.顺序语句 按照顺序从上往下依次执行的语句,中间没有任何的判断和跳转 2.分支语句 根据不同的条件来产生不同的分支 if语句.switch语句 3.循环语句 重复执行某句 ...

  7. Java基础知识拾遗(三)

    集合框架 SortedSet接口,声明了以升序进行排序的行为. Queue接口,声明了队列行为,队列通常是先进先出的列表 Deque接口,扩展了Queue接口,声明了双端队列的行为.双端队列可以像标准 ...

  8. java 基础知识-数组的7种算法(排序、求和、最值、遍历...)

    遍历 遍历就是把这个数组的每个元素 显示出来 遍历的方法就是先定义这个数组的大小,然后用FOR循环来完成数组,例如 double[] score = new double[5]; Scanner in ...

  9. java基础知识查漏 三

    一.Servlet 和Jsp的生命周期 1.Servlet生命周期       Servlet是运行在Servlet容器(有时候也叫Servlet引擎,是web服务器和应用程序服务器的一部分,用于在发 ...

随机推荐

  1. 基于Qt Phonon模块实现音乐播放器

    这次使用Qt实现的是一个本地音乐播放器,可以播放下载在计算机本地的音乐,提供了添加歌曲,歌曲列表,清空列表的功能.默认歌曲列表循环播放.音乐播放的实现主要依赖的是Qt 的多媒体框架phonon.该音乐 ...

  2. 搞ACM的你们伤不起

    这个虽然看过很多遍了,但是还是看着想笑,有时候真的想问问自己为什么这么菜,血流得还不够? 劳资六年前开始搞ACM啊!!!!!!!!!!  从此踏上了尼玛不归路啊!!!!!!!!!!!!  谁特么跟劳资 ...

  3. java程序运行时内存分配详解 (转)

    转自:http://www.tuicool.com/articles/uU77v2 一.  基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Ja ...

  4. kafka0.8.2以下版本删除topic

    一些说明 kafka0.8.2及以上版本已经支持delete命令删除topic,可是之前的版本要是想删除topic还是要费一番手脚,绝对是个体力活... 该方法最好仅在线下开发环境中使用,毕竟要重启z ...

  5. paper 33 :[教程] 如何使用libsvm进行分类

    文章来源:http://www.matlabsky.com/thread-12379-1-1.html 这篇文章的讲解的真的是言简意赅,很简单的例子就把这个入门的门槛降低了不少,目前的情况是,我都晓得 ...

  6. 一天弹出一次广告cookie

    function setCookie(name, value, expire) { window.document.cookie = name + "=" + escape(val ...

  7. 三层与MVC

    三层架构(3-tier architecture) 我们平时总是将三层架构与MVC混为一谈,殊不知它俩并不是一个概念.下面我来为大家揭晓我所知道的一些真相. 首先,它俩根本不是一个概念. 三层架构是一 ...

  8. Subversion简明手册--使用hook svn

    使用 hook ,为了方便管理员 控制提交的过程 Subversion 提供了 hook 机制.当特定的 事件发生时,相应的 hook 会被调用, hook 其实就相当于特定 事件的处理函数.每个 h ...

  9. 关于更改MYECLIPSE JS 代码背景颜色

    白色的背景,看花了眼,你想改一下编辑器的背景颜色,移步这里就可以了. 这时你高兴的打开编辑器,发现颜色确实变了,但是当你打开有JS的JSP时,你碉堡了,发现JS的背景颜色还是默认的, 看着让人纠结,好 ...

  10. NOIP200902分数线划定

    NOIP200902分数线划定 描述 世博会志愿者的选拔工作正在 A 市如火如荼的进行.为了选拔最合适的人才,A 市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试.面试分数线根据 ...