java多线程学习——4种创建多线程的方式

在java中,多线程的创建方式总共有4种,其中继承Thread类与实现Runnable接口这两种方法最简单,但是实际开发过程中用的比较多的是另外两种方式:一种是实现Callable接口的方式来创建多线程,一种是利用线程池创建多线程。后两者相较前两者而言,虽然实现方式上复杂了些,但是都能够定义返回值,同时能够抛出异常。以下是四种方式创建多线程的java代码实例:

1.继承Thread类

public class Test1 extends Thread{
	int sum=0;
	public void run(){
		System.out.println("执行run方法");
		
		for(int i=0;i<50;i++){
			sum+=i;
			System.out.println(Thread.currentThread().getName()+" sum:"+sum);
		}
		
	}
}

2.实现Runnable接口

public class Test2 implements Runnable{
	int sum=0;
	public void run(){
		System.out.println("执行run方法");
		
		for(int i=0;i<50;i++){
			sum+=i;
			System.out.println(Thread.currentThread().getName()+"sum:"+sum);
		}
		
	}
}

3.实现Callable接口,Callable同Runnable不一样的地方在于,需要实现call方法,方法的返回值类型即为实现Callable时的泛型。如下例所示,Integer即为实现的泛型,同时call方法的返回值也必须是Integer。获取返回值需要通过FutureTask类,测试类有示例代码。

public class Test3 implements Callable<Integer>{
	public Integer call() throws Exception {
		int sum=0;
		for(int i=0;i<30;i++){
			sum+=i;
			System.out.println(Thread.currentThread().getName()+" sum:"+sum);
		}
		return sum;
	}
	
}

4.线程池方式

以前常用的创建线程池的方式是:

Executor threadPool = Executors.newFixedThreadPool(10);
for(int i = 0 ;i < 10 ; i++) {
	threadPool.execute(new Runnable() {
		public void run() {
			System.out.println(Thread.currentThread().getName()+" is running");
		}
	});
}

但是阿里java技术规范建议我们不要这样做,因为Executors提供的创建线程的方式都有不同程度的OOM风险。

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

因此我们采用手动创建线程池的方式。

首先引入com.google.guava包

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
        .setNameFormat("demo-pool-%d").build();
//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
        0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown

测试类:

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

/**
 *@date 2017-5-25
 *@description 多线程的三种实现方式测试
 **/
public class MainTest {
	
	/**
	 * 2017-5-25
	 */
	public static void main(String[] args) {
		//继承thread类
		Test1 test1_1 = new Test1();
		Test1 test1_2 = new Test1();
		test1_1.start();
		test1_2.start();
		
		//实现runnable接口
		Test2 test2_1 = new Test2();
		Test2 test2_2 = new Test2();
		Thread a = new Thread(test2_1);
		Thread b = new Thread(test2_2);
		a.start();
		b.start();
		
		//通过实现Callable接口
		Test3 test3_1 = new Test3();
		FutureTask<Integer> ft = new FutureTask<Integer>(test3_1);
		Thread c = new Thread(ft);
		Test3 test3_2 = new Test3();
		FutureTask<Integer> ft2 = new FutureTask<Integer>(test3_2);
		Thread d = new Thread(ft2);
		c.start();
		d.start();
		try {
                    System.out.println(ft.get());         
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
	}

}


扩展:在创建使用多线程的方式3中,我们使用了FutureTask类的方式获取返回值。不过,使用FutureTask类会有一个弊端,那就是如果任务执行时间较长,而我们又需要拿到返回值才能执行后续的操作的话,只能不断的调用FutureTask的get()方法阻塞式的获取值。因此在1.8之前的实际开发中,我们更倾向于使用另一种方式:ExecutorCompletionService。JDK1.8的包中新增了CompletableFuture 和 CompletionStage两个类,这两个类是对Future缺陷的补充。CompletableFuture实现了Future和CompletionStage两个接口。对CompletionStage感兴趣的同学可以看下这篇文章,讲的比较好:https://blog.csdn.net/f641385712/article/details/83580886

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值