java线程三种创建方式

Java中创建线程主要有三种方式:

一、继承Thread类创建线程类(Thread 是类,且实现了Runnable接口)

(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。

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

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

 

方法 说明
void run() 执行操作任务的方法
void start() 使该线程开始执行
void sleep(long millis) 在指定的毫秒内让当前正在执行的线程休眠(暂停执行)
String getName() 返回该线程的名称
int getPriority() 返回该线程的优先级
void setPriority(int newPriority) 更改该线程的优先级
Thread.state getState() 返回该线程的状态
boolean isAlive() 测试线程是否处于活动状态
void join() 等待该线程终止
void interrupt() 中断线程
void yieid()

暂停当前正在执行的线程对象,并执行其他线程

 

 

如:

public class MyThread  extends Thread {
    private  int count=0;
    public void run()
    {
        while (count<100)
        {

            count++;
            System.out.println("count值:"+count);
        }

    }
}
public class MyThreadTest {
    public static void main(String[] args)
    {
        MyThread thread1=new MyThread();
        thread1.start();

        MyThread thread2=new MyThread();
        thread2.start();
    }
}

 

上述代码中Thread.currentThread()方法返回当前正在执行的线程对象。GetName()方法返回调用该方法的线程的名字。

 

二、通过Runnable接口创建线程类

  1避免继承的局限,一个类可以继承多个接口

       具体什么缺陷呢?

  ①首先来从接口实现和类继承的区别来谈谈

  如果你想写一个类C,但这个类C已经继承了一个类A,此时,你又想让C实现多线程。用继承Thread类的方式不行了。(因          为单继承的局限性),此时,只能用Runnable接口,Runnable接口就是为了解决这种情境出现的

   2 适合于资源的共享

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

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

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

实例Runnable

public class MyRunnable  implements  Runnable{
private int tickets = 3;


@Override
public void run()
{
while (tickets > 0) {
tickets--; // 如果还有票就卖一张
System.out.println("剩余票数为:" + tickets);
}


}
}
测试:
MyRunnable thread = new MyRunnable();
new Thread(thread).start();//同一个mt,但是在Thread中就不可以,如果用同一
new Thread(thread).start();//个实例化对象mt,就会出现异常
new Thread(thread).start();

结果:

剩余票数为:1
剩余票数为:1
剩余票数为:0

实例Thread

public class MyThread  extends Thread {
private int tickets =3;

@Override
public void run()
{
while (tickets > 0) {
tickets--; // 如果还有票就卖一张
System.out.println("剩余票数为:" + tickets);
}


}
}

测试:

MyThread mts = new MyThread();
new Thread(mts).start(); //启动 n 个线程
MyThread mts2 = new MyThread();
new Thread(mts2).start();
MyThread mts3 = new MyThread();
new Thread(mts3).start();

结果:

剩余票数为:2
剩余票数为:2
剩余票数为:1
剩余票数为:0
剩余票数为:1
剩余票数为:0
剩余票数为:2
剩余票数为:1
剩余票数为:0

总结:

Thread类也是Runnable接口的子类,可见, 实现Runnable接口相对于继承Thread类来说,有如下显著的好处:

  • 适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效的分离,较好地体现了面向对象的设计思想。

  • 可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。

  • 有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程操作相同的数据,与它们的代码无关。当共享访问相同的对象是,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例

 

三、通过Callable和Future创建线程

 

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

(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

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

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

 

实例代码:

/*
创建Callable接口的实现类,并实现clall()方法
*/
public class MyCallable implements Callable {

private int i = 0;

// 与run()方法不同的是,call()方法具有返回值
@Override
public Integer call() {
int sum = 0;
for (; i < 50; i++) {
// System.out.println(Thread.currentThread().getName() + " " + i);
sum += i;
}
return sum;
}

}

 

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class MyCallableText {

public static void main(String[] args) {

//并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程
Callable myCallable = new MyCallable(); // 创建MyCallable对象
FutureTask ftk = new FutureTask(myCallable); //使用FutureTask来包装MyCallable对象

for (int i = 0; i < 50; i++) {
// System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
Thread thread = new Thread(ftk); //FutureTask对象作为Thread对象的target创建新的线程
thread.start(); //线程进入到就绪状态
}
}

System.out.println("主线程循环执行完毕..");


int sum = 0; //取得新创建的新线程中的call()方法返回的结果
try {
sum = ftk.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("sum = " + sum);


}
}

结果:

主线程循环执行完毕..
sum = 1225

 

 

 

四、创建线程的三种方式的对比

采用实现Runnable、Callable接口的方式创见多线程时,

Runnable和Callable的区别是,

  (1)Callable规定的方法是call(),Runnable规定的方法是run()。

  (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得

  (3)call方法可以抛出异常,run方法不可以

  (4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。

优势是:

1 线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。

在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

2与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。

 

劣势是:

编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。

使用继承Thread类的方式创建多线程时优势是:

编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。

Thread劣势是:

线程类已经继承了Thread类,所以不能再继承其他父类。

你可能感兴趣的:(java线程三种创建方式)