java创建线程的方法

1.1      创建线程

1.1.1     无返回值的线程创建

package com.first;

public class ThreadTest

{

public static void main(String[] args)  {

System.out.println("主线程ID:"+Thread.currentThread().getId());

MyThread thread1 = new MyThread("thread1");//(1)继承thread类,启动线程

thread1.start();

MyThread thread2 = new MyThread("thread2");//(2)继承thread类,直接调用方法

thread2.run();

MyRunnable runnable = new MyRunnable();//(3)实现Runnable方法,作为入参

Thread thread3= new Thread(runnable);

thread3.start();

Thread thread4 = new MyThread(runnable);//(4)继承类也实现接口,实际上用的还是类中的run方法;thread run

thread4.start();

}

}

class MyThread extends Thread//(1)继承thread类,重写run方法

{

private String name;

public MyThread(String name){

this.name = name;

}

public MyThread(Runnable runnable){//(4)Runnable入参传入

super(runnable);

}

@Override

public void run()

{

System.out.println(" thread run name:"+name+" 子线程ID:"+Thread.currentThread().getId());

}

}

class MyRunnable implements Runnable{//(3)实现runable方法

public MyRunnable()

{

}

@Override

public void run() {

System.out.println("MyRunnable 子线程ID:"+Thread.currentThread().getId());

}

}

运行结果

主线程ID:1

thread run name:thread2 子线程ID:1

thread run name:thread1 子线程ID:11

MyRunnable 子线程ID:13

thread run name:null 子线程ID:14

线程Thread实际上是实现了Runable接口,class Thread implements Runnable{},并且定义了一个引用private Runnable target;用于保存构造函数传入的继承类引用MyRunnable的入参,public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);} ,Thread重写了Runable接口的run函数

public void run() {

if (target != null) {

target.run();

}

}

所以如果是情况(1)子类继承Thread类,重写run()方法,则target为null,Thread类的run方法实现也没有用,因为被子类重写了。调用的是子类实现的方法;如果是情况(2),没有启动线程而是直接调用子类的run方法,则跟调用一般方法一样,只不过是主线程在调用方法,thread2被创建,但是没有被启动;如果像情况(3)因为传入了MyRunable对象的引用,所以target不在为空,而且没有子类重写Thread的run()方法,所以会直接调用Thread默认的run()方法,target不为空,所以执行的是传入的MyRunable的方法;如果是情况(4)即传入了MyRunable的方法,子类也继承实现了run()方法,则按照顺序,MyRunable作为入参传入,MyThread子类调用了supuer的构造函数,传给父类的target。因为MyThread子类,重写父类的run方法,所以,无论是否传入target参数,Thread类的run()方法实现都会被MyThread子类的run()方法重写。所以最后执行的是MyThread子类中实现的run方法。

总结下创建线程的方法主要有两种:(1)继承Thread类,重写该类的run()方法.(2)实现Runnable接口,实现接口的run方法,作为Thread构造函数的入参传入任务。Thread的start方法来创建一个新线程来执行该子任务。如果调用Runnable的run方法的话,是不会创建新线程的,这跟普通的方法调用没有任何区别。

这2种方式都可以用来创建线程去执行子任务,具体选择哪一种方式要看自己的需求。直接继承Thread类的话,可能比实现Runnable接口看起来更加简洁,但是由于Java只允许单继承,所以如果自定义类需要继承其他类,则只能选择实现Runnable接口。

1.1.2     有返回值的线程创建

上述两种方法,在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。所以需要有返回值的线程实现。基于FutureTask类,Callable接口,Runnable, Future接口实现带返回值的线程。Runnable 接口是提供run方法,FutureTask实现接口的run方法,作为线程的执行方法。Future接口则是提供了几个函数,用来操作线程的执行,获取线程返回值。FutureTask实现了RunnableFuture接口,RunnableFuture继承了Runnable, Future接口。Callable接口只有一个带返回值的call函数,需要继承实现Callable的call函数,call函数是线程真正要执行的内容,在FutureTask中实现的run方法中会调用call函数来执行线程的任务内容。

(1)FutureTask实现了RunnableFuture接口

public class FutureTask<V> implements RunnableFuture<V>

(2)RunnableFuture继承了Runnable, Future接口

public interface RunnableFuture<V> extends Runnable, Future<V>

{

void run();

}

(3)FutureTask构造函数

public FutureTask(Callable<V> callable) {

if (callable == null)

throw new NullPointerException();

 this.callable = callable;// FutureTask定义callable引用指向Callable对象

this.state = NEW;       // ensure visibility of callable

}

(4)Callable的定义

public interface Callable<V> {

V call() throws Exception;//只有一个call函数,线程执行任务

}

(5)FutureTask中run函数的实现

public void run() {//实现Runable接口的run函数

if (state != NEW ||

!UNSAFE.compareAndSwapObject(this, runnerOffset,

null, Thread.currentThread()))

return;

try {

  Callable<V> c = callable;//赋值引用

if (c != null && state == NEW) {

V result;

boolean ran;

try {

result = c.call();//调用了callable的call函数

ran = true;

} catch (Throwable ex) {

result = null;

ran = false;

setException(ex);

}

if (ran)

set(result);//将执行结果赋值给outcome引用

}

} finally {

// runner must be non-null until state is settled to

// prevent concurrent calls to run()

runner = null;

// state must be re-read after nulling runner to prevent

// leaked interrupts

int s = state;

if (s >= INTERRUPTING)

handlePossibleCancellationInterrupt(s);

}

}

(6)FutureTask中的set函数

protected void set(V v) {

if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {

 outcome = v;//执行结果赋值给outcome

UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state

finishCompletion();

}

}

(7)FutureTask中get()函数

public V get() throws InterruptedException, ExecutionException {

int s = state;

if (s <= COMPLETING)

s = awaitDone(false, 0L);//等待线程执行完毕

return report(s);

}

(8)FutureTask中report函数返回执行结果

private V report(int s) throws ExecutionException {

Object x = outcome;//返回线程的执行结果

if (s == NORMAL)

 return (V)x;//返回执行结果

if (s >= CANCELLED)

throw new CancellationException();

throw new ExecutionException((Throwable)x);

}

(9)Future接口的方法定义

public interface Future<V> {

boolean cancel(boolean mayInterruptIfRunning);

boolean isCancelled();

boolean isDone();

 V get() throws InterruptedException, ExecutionException;//线程操作方法

V get(long timeout, TimeUnit unit)

throws InterruptedException, ExecutionException, TimeoutException;

}

综上所述,FutureTask实现Runable接口,是为了实现线程执行函数run方法。FutureTask实现future接口,是为了实现Future操作线程的方法,例如V get()返回执行结果。FutureTask以Callable为入参,是要执行Callable中的线程任务call()方法。FutureTask的run()方法中会调用Callable的call()方法。

所以给出实际的例子

package com.first;

import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

public class ThreadTest

{

public static void main(String[] args)  {

// 使用FutureTask来包装Callable对象

ThreadByCallable rt = new ThreadByCallable();//创建任务对象

FutureTask<Integer> task = new FutureTask<Integer>(rt);//(5)使用

// task继承了Runable接口,所以可以作为Thread入参

new Thread(task, "有返回值的线程").start();

try {

// 获取线程返回值

System.out.println("thread5:返回值:" + task.get());

} catch (Exception ex) {

ex.printStackTrace();

}

}

}

class ThreadByCallable implements Callable<Integer> {//创建类实现Callable接口

@Override

public Integer call() {

System.out.println("thread5:call" + Thread.currentThread().getName());

// call()方法有返回值

return 5;

}

}

原文地址:https://www.cnblogs.com/bclshuai/p/10245149.html

时间: 2024-08-27 08:01:45

java创建线程的方法的相关文章

Java 创建线程的方法

为了偷懒少敲几个字这里我写了一个Util类: 1 package test; 2 3 public class Util { 4 static void println() {System.out.println();} 5 static void println(Object obj) {System.out.println(obj);} 6 } 并且在之后的代码中都加入了: 1 package test; 2 import static test.Util.*; 1.实现Runnable接口

随笔 ① 关于java线程 --- 创建线程的方法

java提供了三种创建线程的方法: 通过继承 Thread 类本身: 通过实现 Runnable 接口: 通过 Callable 和 Future 创建线程. 方法一:通过继承Thread类 ① 定义Thread类的子类,并重写该类的run()方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. ② 创建Thread子类的实例,即创建线程对象. ③ 调用线程对象的start()方法来启动该线程. 示例: package com.thread; public cla

程序员:java中直接或间接创建线程的方法总结

在java开发中,经常会涉及多线程的编码,那么通过直接或间接创建线程的方法有哪些?现整理如下: 1.继承Thread类,重写run()方法 class Worker extends Thread { @Override public void run() { System.out.println("Code run in a sub thread!"); } } public class CreateThreadTester { public static void main(Stri

java 创建线程

java创建线程有3种方式: (1)继承Thread(2)实现Runnable接口(3)实现Callable接口 1.继承Thead package com.java.thread; public class ThreadClient { public static void main(String[] args) { Print p1 = new Print(); Print p2 = new Print(); p1.start(); p2.start(); } } class Print e

Java创建线程的三种主要方式

Java创建线程的主要方式 一.继承Thread类创建 通过继承Thread并且重写其run(),run方法中即线程执行任务.创建后的子类通过调用 start() 方法即可执行线程方法. 通过继承Thread实现的线程类,多个线程间无法共享线程类的实例变量.(需要创建不同Thread对象,自然不共享) 例子: /** * 通过继承Thread实现线程 */ public class ThreadTest extends Thread{ private int i = 0 ; @Override

(转)java创建线程的两种方法比较

Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线程,有两种方法: ◆需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法:  ◆实现Runnalbe接口,重载Runnalbe接口中的run()方法. 为什么Java要提供两种方法来创建线程呢?它们都有哪些区别?相比而言,哪一种方法更好呢? 在Java中,类仅支持单继承

Java创建线程的两个方法

Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线程,有两种方法: ◆需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法: ◆实现Runnalbe接口,重载Runnalbe接口中的run()方法. 为什么Java要提供两种方法来创建线程呢?它们都有哪些区别?相比而言,哪一种方法更好呢? 在Java中,类仅支持单继承,

Java 创建线程的两种方法

Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线程,有两种方法: ◆需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法: ◆实现Runnalbe接口,重载Runnalbe接口中的run()方法. 为什么Java要提供两种方法来创建线程呢?它们都有哪些区别?相比而言,哪一种方法更好呢? 在Java中,类仅支持单继承,

JAVA中创建线程的方法及比较

JAVA中提供了Thread类来创建多线程的应用,常用的方式有以下2种. 一.实现Runnable接口来创建线程 1.创建一个任务类,实现Runnable接口,并重写run()方法,run()方法中的内容就是需要线程完成的任务. 2.创建一个任务类的对象. 3.任务类必须在线程中执行,因此将任务类的对象作为参数,创建一个Thread类对象,该Thread类对象才是真正的线程对象. 4.调用Thread线程类对象的start()方法,来启动一个线程. 代码实例: 1 public class Te