java多线程创建runnable_java多线程创建-Thread,Runnable,callable和threadpool

java创建多线程的方式有许多种,这里简要做个梳理

1. 继承Thread类

继承java.lang.Thread类,创建本地多线程的类,重载run()方法,调用Thread的方法启动线程。示例代码如下:

MyThread.java

public class MyThread extends Thread {

public void run(){

private int copy = 0;

System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());

System.out.println("Thread serialnum:" + ++copy);

try {

sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());

}

public static void main(String[] args){

MyThread mt1 = new MyThread();

MyThread mt2 = new MyThread();

MyThread mt3 = new MyThread();

System.out.println("Start all Threads:");

mt1.start();

mt2.start();

mt3.start();

}

}

输出结果:

Start all Threads:

Thread id:Thread-0 == print time:1495975884383

Thread serialnum:1

Thread id:Thread-1 == print time:1495975884383

Thread serialnum:1

Thread id:Thread-2 == print time:1495975884383

Thread serialnum:1

Thread id:Thread-1 == print time:1495975885385

Thread id:Thread-0 == print time:1495975885385

Thread id:Thread-2 == print time:1495975885385

2. 实现Runnable接口

实现java.lang.Runnable接口的run方法,使用实现的对象实例化Thread类,调用Thread对象的start()方法。

示例代码:

public class MyRunnable implements Runnable {

private int copy = 0;

public void run(){

System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());

System.out.println("Thread serialnum:" + ++copy);

try {

sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());

}

public static void main(String[] args){

MyRunnable mr = new MyRunnable();

System.out.println("Start all Threads:");

new Thread(mr).start();

new Thread(mr).start();

new Thread(mr).start();

}

}

输出结果:

Start all Threads:

Thread id:Thread-0 == print time:1495975833588

Thread id:Thread-1 == print time:1495975833588

Thread serial:1

Thread id:Thread-2 == print time:1495975833588

Thread serial:2

Thread serial:3

Thread id:Thread-0 == print time:1495975834603

Thread id:Thread-1 == print time:1495975834603

Thread id:Thread-2 == print time:1495975834603

对比Thread方法和Runnable方法的使输出结果不难发现:

. 二者均可实现多线程并发效果

. Runnable的方法可以使用一个Runnable对象创建多个线程,这多个线程共享其依赖的Runnable对象的资源,适用于多个线程处理相同资源的场景(网上举得较多的例子:卖票);Thread的方法则是完全相互独立的线程

事实上,嫌贵而言,当前Runnable使用的要比Thread方法普遍的多,除了上面说的资源共享的原因之外,Java的单继承特性也增大了Thread方法的局限性。

3. 实现Callable接口

相对于上述继承Thread类的方法和实现Runnable接口的方法,实现Callable接口的方法不但可以可以实现多线程并发,还能够处理线程的返回值或者获取执行异常。使用Callable实现多线程编程需要实现Callable的call方法(在call方法中指定返回值,抛出异常),构造与之关联的FutureTask对象,启动线程后,线程执行的结果会存储在FutureTask对象中,可以使用FutureTask的get方法获取。示例代码:

import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

import static java.lang.Thread.sleep;

public class MyCallable implements Callable {

private int flag = 0;

public Integer call() throws Exception {

System.out.println("Thread id:" + Thread.currentThread().getName() + " == print time:"+System.currentTimeMillis());

sleep(10000);

System.out.println("Thread id:" + Thread.currentThread().getName() + " == print time:"+System.currentTimeMillis());

++flag;

return flag;

}

public static void main(String[] args) throws Exception{

MyCallable myCallable = new MyCallable();

FutureTask future = new FutureTask(myCallable);

FutureTask future2 = new FutureTask(myCallable);

new Thread(future).start();

new Thread(future2).start();

int Result,Result2;

// while (!future.isDone());

Result = future.get();

//

// while(!future2.isDone());

Result2 = future2.get();

System.out.println("GET THREAD NAME:"+ Result );

System.out.println("GET THREAD NAME 2:"+Result2);

}

}

执行结果:

Thread id:Thread-0 == print time:1495997744617

Thread id:Thread-1 == print time:1495997744617

Thread id:Thread-0 == print time:1495997754625

Thread id:Thread-1 == print time:1495997754625

GET THREAD NAME:1

GET THREAD NAME 2:2

上述代码执行逻辑与前面Runnale的示例代码类似,通过构造Thread对象来启动多线程。区别在于此处构造了futureTask方法用来用来存储线程返回值。需要注意的是,线程的Callable泛型接口里的类型和call()方法的返回值类型和FutureTask的泛型接口类型要一致。

4. 使用线程池和Executor框架

前面的三种方案,我们创建了Runnable或者Callable或者Thread的任务,扔到Thread中去启动,我们需要手动去管理各种多线程的参数,比如线程数量,线程复用,线程安全的控制等。Java5以后的版本提供了Executor技术,能够提供搭建好的线程池,为多线程提供了完整的解决方案,能够有效的管理线程数量,线程复用策略,保证线程安全,避免this逃逸问题等。

Executor提供的线程池方案包括newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool和SingleThreadExecutor(Fork/Join框架还提供了一个newWorkStealingPool),这些线程池分别提供了不同的线程管理方案,执行返回一个ExecutorService对象,这个对象可以调用execute()方法或者submit()方法,将前面定义的Runnable任务或者Callable任务或者Thread任务提交到各个线程去执行

我们以比较常用的newCachedThreadPool()为例,下面示例代码使用ExecutorService执行一个Callable对象任务,获取每个线程的返回值。

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.*;

import static java.lang.Thread.sleep;

public class MyCallable2 implements Callable {

public String call() throws Exception{

sleep(1000);

System.out.println("terminate the thread : "+Thread.currentThread().getName());

return Thread.currentThread().getName();

}

public static void main(String[] args){

ExecutorService es = Executors.newCachedThreadPool();

List> futureList = new ArrayList>();

for(int i=0;i<5;i++){

Future future = es.submit(new MyCallable2());

futureList.add(future);

}

for (Future f: futureList

) {

while(!f.isDone());

try {

System.out.println("EXECUTE RESULT:"+f.get());

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

finally {

es.shutdown();

}

}

}

}

执行结果如下:

terminate the thread : pool-1-thread-5

terminate the thread : pool-1-thread-4

terminate the thread : pool-1-thread-3

terminate the thread : pool-1-thread-2

terminate the thread : pool-1-thread-1

EXECUTE RESULT:pool-1-thread-1

EXECUTE RESULT:pool-1-thread-2

EXECUTE RESULT:pool-1-thread-3

EXECUTE RESULT:pool-1-thread-4

EXECUTE RESULT:pool-1-thread-5

使用Executors创建Runnable线程与创建Callable线程的方法类似,且不用管理返回值,相对更加简单,此处不再赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值