Java创建线程的4种方式及优缺点

版权声明:本文为博主原创文章,转载需在开头注明出处 https://blog.csdn.net/zfq_lsh/article/details/84679867

目录

1. 通过继承Thread类实现

2. 通过实现Runnable接口实现

3. 通过lambda的方式实现

4. 通过Callable和Future创建线程 

5. 通过继承Thread类实现 代码展示

 6. 通过实现Runnable接口实现代码展示

7. 通过lambda的方式实现代码展示

8. 通过Callable和Future创建线程  代码展示


1. 通过继承Thread类实现

    特点: Java是单继承, 继承Thread类之后无法再继承其他类

                需要为每个需要线程执行的方法单独创建一个class文件,开发效率较低

                一般不推荐使用

2. 通过实现Runnable接口实现

    特点: 只需要实现Runnable接口, 不影响正常代码结构

                可以通过匿名内部类的方式实现, 开发简单

3. 通过lambda的方式实现

     特点 : 简单、快速、高效

                 不在拘泥于run(), 可以用线程执行任何方法

                  jdk8以后才支持本语法

4. 通过Callable和Future创建线程 

    特点: 可以获取到线程处理完成结果的返回值, 在特定情况下使用

               代码复杂, 开发成本较高

代码实现

5. 通过继承Thread类实现 代码展示

/**
 * 	继承Thread实现多线程
 * @author Salen
 *
 */
public class MyThread extends Thread{

	private int count = 5;
	
	/**
	 * 重写父类中的run(), 执行具体的业务逻辑
	 */
	public void run() {
		count--;
		System.out.println(count);
	}
	
	public static void main(String[] args) {
		//1. 创建线程对象的实例, 该对象必须继承Thread类及重写了run()
		MyThread my = new MyThread();
		
		//2. 创建多个线程的实例, 进入线程的初始化状态
		Thread t1 = new Thread(my);
		Thread t2 = new Thread(my);
		Thread t3 = new Thread(my);
		
		/*3. 启动线程, 线程只有执行start()之后才算是真正的启动, 才会执行run()方法里面的具体逻辑
		 	线程启动后会进入线程的就绪状态,等待CPU的调用*/
		t1.start();
		t2.start();
		t3.start();
	}
}

 6. 通过实现Runnable接口实现代码展示

/**
 * 通过实现Runnable接口启动一个线程
 * @author Salen
 */
public class RunbleThread {
	
	public static void main(String[] args) {
		// 1. 正规启动一个线程
		startNormalThread();
		
		//2. 简化的启动一个线程
		startSimpleThread();
	}
	
	/**
	 * 正常启动一个线程
	 */
	public static void startNormalThread() {
		
		//1. 创建一个线程对象, 通过匿名内部类实现Runnable接口重写run()方法, 完成后线程进入初始化状态
		Thread t = new Thread(new Runnable() {
			
			//2. 重写run(), 执行具体的业务逻辑
			@Override
			public void run() {
				//Thread.currentThread().getName() 获取当前线程的名称 :"我是线程名称, 可以不要我这个参数"
				//如果未指定线程名称,系统会自动为线程分配一个名称
				System.out.println(Thread.currentThread().getName() + " : 我在工作zhong....");
			}
		}, "我是线程名称, 可以不要我这个参数");
		
		/*3. 启动线程, 线程只有执行start()之后才算是真正的启动, 才会执行run()方法里面的具体逻辑
	 	线程启动后会进入线程的就绪状态,等待CPU的调用*/
		t.start();
	}
	
	/**
	 *  简化的启动一个线程
	 */
	public static void startSimpleThread() {
		//1. 创建一个线程对象 
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + " : 我在工作zhong....");
			}
		}, "我是线程名称, 可以不要我这个参数").start(); //创建完对象之后直接启动本线程
	}
	
}

7. 通过lambda的方式实现代码展示

/**
 * 通过lambda的方式启动一个新线程
 * @author Salen
 */
public class LambdaThread {

	public static void main(String[] args) {
		//3. lambda的方式启动一个线程, jdk8以后支持本方式, 可以指定任何方法通过线程的方式执行
		new Thread(() -> dealService()).start();
	}
	
	/**
	 * 普通的业务处理方法
	 */
	public static void dealService() {
		System.out.println(Thread.currentThread().getName() + " : 我在工作zhong....");
	}
}

8. 通过Callable和Future创建线程  代码展示

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

/**
 * 通过Futrue和callable实现多线程
 * @author Salen
 */
public class CallableThread {

	public static void main(String[] args) {
		//1. 创建一个实现了callable接口的对象实例
		MyCallable myCallable = new MyCallable("线程一", 3);
		
		//2. 将实例放入到FutureTask中, 泛型必须与MyCallable中call方法的返回值类型保持一致
		FutureTask<Object> thread = new FutureTask<>(myCallable);
		
		//3. 启动线程
		new Thread(thread).start();
		
		//4. 获取线程的返回结果
		try {
			Object result = thread.get();
			System.out.println(result.toString());
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
	}
}

/**
 * 实现Callable接口
 * @author Salen
 */
class MyCallable implements Callable<Object>{

	private int id;
	private String name;
	/**
	 * 通过构造函数进行传参, 其可以实现其他方法(例如getter,setter)方式进行参数传递
	 */
	public MyCallable(String name, int id) {
		this.id = id;
		this.name = name;
	}
	
	/**
	 * 线程启动后调用本方, 类似于run()
	 */
	@Override
	public Object call() throws Exception {
		System.out.println(Thread.currentThread().getName() + "我是回调函数");
		return 1;
	}
}

猜你喜欢

转载自blog.csdn.net/zfq_lsh/article/details/84679867