Java多线程之线程创建和启动

原创 2016年05月31日 20:11:29

Java使用Thread类表示线程,所有的线程对象必须是Thread类或其子类的实例,每个线程的作用,实际上就是执行一段程序刘,java使用线程执行体来代表着段程序流

创建线程3方法

继承Thread类

  • 创建线程的方法1是继承Thread类,重写run()方法,该方法的方法体代表了线程需要完成的任务,因此run()方法叫做线程执行体

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

  • 启动线程应该用线程对象的start()方法

public class FirstThread extends Thread {
    private int i;
    @override
    public void run(){
        //继承Thread时,用this即可获取当前线程
        for(;i < 100; i++){
            System.out.println(this.getName() + " " + i);
        }
    }
}

public static void main(String[] args){
    for(int i = 0; i < 100; i++){
        //用Thread的静态方法获取当前主线程名称
        System.out.println(Thread.currentThread().getName());
        if(i == 20){
        //除主线程,另外启动2个线程
            new FirstThread().start();
            new FirstThread().start();
        }
    }
}

实现Runnable接口

  • 创建线程方法2,实现Runnable接口,重写run()方法

  • 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该对象才是真正的线程对象。通俗来说,就是用Thread来包装实现了Runnable接口的实例

  • 调用start()方法,启动线程

SecondThread st = new SecondThread();
new Thread(st).start();

//也可以指定新线程的名称
new Thread(st,"新线程1").start();

//以上两条线程会共享st实例的变量
public class FirstThread implements Runnable {
    private int i;
    @override
    public void run(){
        //实现Runnable接口,只能用Thread.currentThread()获取当前线程
        for(;i < 100; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

使用Runnable接口创建的多线程可以共享线程类的实例变量。因为这种方式下,程序创建的Runnable对象只是线程的target,而多个线程可以共享一个target

使用Callable和Future创建线程

JDK 1.5后,java.util.concurrent包下的Callable接口,它像是Runnable接口的增强版。Callable接口的call()方法可以作为线程的执行体,比run()方法强大。

那么,完全可以在Thread的target中传入一个Callable对象,执行体是call()方法。但问题在于:Callable不是Runnable的子接口,是JDK1.5新增接口,而且还有返回值

JDK 1.5提供了Future接口来代表Callable接口里call()方法的返回值,FutureTask是Future的实现类,并且实现了Runnable接口,那么可以作为Thread类的target

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result 返回运行结果
     * @throws Exception if unable to compute a result 若不能运算则抛出异常
     */
    V call() throws Exception;
}
public interface Future<V> {
    //取消该Future关联的Callable任务
    boolean cancel(boolean mayInterruptIfRunning);
    //如果Callable任务正常完成前被取消,返回true;完成后,不能取消  
    boolean isCancelled();
    //如果Callable任务完成,返回true 
    boolean isDone();
    //返回Callable任务里call()方法的返回值。调用该方法将导致程序阻塞,须等到子线程结束才会得到返回值,也就是异步的 
    V get() throws InterruptedException, ExecutionException;
    //与上一样,不过可以设置最多阻塞timeout时间,时间单位为unit,若超时,抛异常    
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

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

  • 创建Callable接口实现类,并实现call()方法

  • 使用FutureTask类来包装Callable对象,FutureTask封装了Callable的call()方法返回值

  • 创建Thread类的对象,传入FutureTask对象作为target,start()启动线程

  • 使用FutureTask对象的get()方法获取线程返回值

public class ThirdThread {


    public static void main(String[] args) {

        ThirdThread rt = new ThirdThread();
        //FutureTask包装Callable对象
        FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                int i = 0;
                for (; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + " 循环值" + i);
                }
                return i;
            }
        });

        for(int i = 0; i < 100; i++){
            //用Thread的静态方法获取当前主线程名称
            System.out.println(Thread.currentThread().getName() + " 循环值" + i);
            if(i == 20){
            //除主线程,另外启动1个线程
                new Thread(task,"有返回值的线程").start();

                try {
                    System.out.println("子线程返回值 " + task.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
//结果部分
有返回值的线程 循环值96
有返回值的线程 循环值97
有返回值的线程 循环值98
有返回值的线程 循环值99
子线程返回值 100
main 循环值21
main 循环值22
main 循环值23
main 循环值24

三种方式对比

继承Thread类,实现Runnable或Callable接口。实现接口实现多线程的方式大体相同

实现接口的优缺点:
Pros:

  • 线程类实现了Runnable或Callable接口,可继承其他类

  • 多个线程可以共享一个target对象(一个Runnable对象),所以适合多个相同线程处理同一个资源,从而将CPU,代码和数据分开,形成清晰的模型

Cons:

  • 编程稍微复杂,若要访问当前线程,只能用Thread.currentThread()

继承Thread的优缺点:
Pros:

  • 编写简单,this即可获得当前线程

Cons:

  • 不能再继承其他类

综上,推荐使用Runnable或Callable接口

版权声明:本文为博主原创文章,未经博主允许不得转载。

java 多线程等待与唤醒机制

java 并发编程网站 :http://ifeve.com/java-7-concurrency-cookbook/ 一: 1:JVM线程状态 NEW, RUNNABLE, BLOC...
  • baiducheng
  • baiducheng
  • 2017年12月25日 16:08
  • 60

java 多线程 future 基本原理

/** * Date:2016年9月7日下午7:56:03 * Copyright (c) 2016, www.bwbroad.com All Rights Reserved. * */ p...
  • xuejianxinokok
  • xuejianxinokok
  • 2016年09月12日 22:23
  • 514

Java基础多线程之线程创建

都知道要实现多线程有两种方法1、继承自Thread类 2、实现Runnable接口 前者很好理解,你想拥有某种性质就简单的办法就是继承它。比如你想很有钱,最简单的办法就是你爸是李刚! 由于java...
  • nnmmbb
  • nnmmbb
  • 2012年07月17日 18:45
  • 664

java多线程之-线程创建方式

线程创建的几种方式 继承Thread类 public class Thread01 extends Thread{ @Override public void run()...
  • RunningXiaoHei
  • RunningXiaoHei
  • 2017年12月01日 12:15
  • 31

多线程之线程创建

Thread,多线程
  • txw910
  • txw910
  • 2017年01月08日 22:17
  • 124

java多线程——线程间通信之线程等待唤醒机制

三个方法 wait() notify() notifyAll() 三个方法都使用在同步中,因为要对持有锁(又叫监控)的线程操作。 所以要使用在同步中,因为只有同步才具有锁。 为什么这些操作线...
  • u011402596
  • u011402596
  • 2015年04月10日 01:16
  • 895

多线程之线程创建的两种方法(Java)

方法1:通过Thread继承类,修改run()方法来实现多线程。 package 线程的创建1; public class example1 { public static void main(...
  • hdd871532887
  • hdd871532887
  • 2015年12月29日 23:17
  • 268

java多线程之启动,停止线程

线程的启动 启动线程的两种方式 暂停线程 停止线程 线程的优先级 守护线程 线程的启动 启动线程的两种方式 继承Thread类 线程代码: package com.su...
  • sunpeng_sp
  • sunpeng_sp
  • 2016年10月19日 22:34
  • 1641

java线程创建和启动

创建一个线程可以有3中方法: 1.继承Thread类  2.实现Runnable接口  3.实现Callable接口  第1种和第2种不会有返回值,第3种可以有返回值. class NewThre...
  • xue_changkong
  • xue_changkong
  • 2016年05月17日 11:31
  • 222

多线程之使用信号量

引言信号量作为GCD的一部分,常用于多线程或任务间协作,当一个任务的执行过程中需要依赖另一个任务时即可使用信号量。实现原理信号量通过信号计数来实现。其使用即计数过程可分为三个部分:创建信号量、等待信号...
  • l964968324
  • l964968324
  • 2015年09月10日 18:56
  • 438
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java多线程之线程创建和启动
举报原因:
原因补充:

(最多只允许输入30个字)