当前位置: 移动技术网 > IT编程>开发语言>Java > java中线程实现方式(execute和submit方式的区别)

java中线程实现方式(execute和submit方式的区别)

2020年08月10日  | 移动技术网IT编程  | 我要评论
1. Java中多线程有哪几种实现方式?继承 Thread 类并重写run方法实现Runnable接,重写run方法实现 Callable 接口,通过FutureTask包装器来创建Thread线程通过线程池创建线程1.1继承 Thread 类并重写run方法java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承 java.lang.Thread 类或者直接调用Runnab

1. Java中多线程有哪几种实现方式?

  • 继承 Thread 类并重写run方法
  • 实现Runnable接,重写run方法
  • 实现 Callable 接口,Callable的任务执行后可返回值,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞。
  • 通过线程池创建线程

2. 执行execute()方法和submit()方法的区别是什么呢?

  • execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
  • submit()方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功,并且可以通过 Future 的 get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
1.1继承 Thread 类并重写run方法

java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承 java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。
在这里插入图片描述

/**
 * 继承 Thread 类并重写run方法
 */ public class T01CreateThread01 extends Thread { private int i; @Override public void run() { for (; i < 100; i++) { System.out.println(getName() + ":" + i + "  (run) "); } } public static void main(String[] args) { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + ":" + i + "  (main)"); if (i == 20) { new T01CreateThread01().start(); new T01CreateThread01().start(); } } } } 
  • 两个线程输出的i变量不连续,因为每次创建线程对象时都需要创建一个ThreadTest对象,所以两线程不能共享该实例变量。

  • 调用start方法后线程并没有马上执行而是进入就绪状态,等待获取CPU资源后才会真正处于运行状态。

  • 使用继承的优点:在 run() 方法内获取当前线程可直接使用 this ,无须使用 Thread.cunrrentThread() 方法。

  • 缺点:Java不支持多继承,继承Thread类后就不能继承其他类了;多个线程之间不能共享线程类的实例变量。

1.2实现Runnable接口的run方法

在这里插入图片描述

/**
 *实现 Runnable 接口的 run 方法
 */ public class T01CreateThread02 implements Runnable { private int i; @Override public void run() { for (; i < 100; i++) { System.out.println(Thread.currentThread().getName() + ":" + i + "(run)"); } } public static void main(String[] args) { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + ":" + i + "(main)"); if (i == 20) { T01CreateThread02 r = new T01CreateThread02(); new Thread(r, "新线程1").start(); new Thread(r, "新线程2").start(); } } } } 
  • 优点:还可以继承其他类; 多个线程共享同一个target对象,所以适合多个相同线程来处理同一个份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,体现了面向对象的思想。
  • 缺点:如果需要访问当前线程,必须使用 Thread.currentThread() 的方法; 和继承方法一样没有返回值
1.3实现 Callable 接口

在这里插入图片描述
在这里插入图片描述
如何理解实现Callable接口的方式创建多线程比实现Runnable接口的方式更强大?

  • call可以有返回值
  • 2.call可以抛出异常,被外面的操作捕获,获取异常的信息
  • 3.Callable是支持 泛型的
/**
 * 实现 Callable 接口
 */ import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; //1.创建一个实现Callable的实现类 public class T01CreateThread04 implements Callable<Integer> { private int i; //2.实现call方法,将此线程需要执行的操作声明在call中 @Override public Integer call() throws Exception { for (; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " : " + i + "  (run)"); } return i; } public static void main(String[] args) { //3.创建Callable接口实现类的对象 T01CreateThread04 c = new T01CreateThread04(); //4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask对象 FutureTask<Integer> futureTest1 = new FutureTask<>(c); FutureTask<Integer> futureTest2 = new FutureTask<>(c); for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " : " + i + "  (main)"); if (i == 20) { //5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start() new Thread(futureTest1, " 新线程1 ").start(); new Thread(futureTest2, " 新线程2 ").start(); } } try { //6.获取Callable中call方法的返回值 //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值 System.out.println("线程返回值:" + futureTest2.get()); } catch (Exception e) { e.printStackTrace(); } } } 
1.4使用线程池

在这里插入图片描述
在这里插入图片描述
好处:

  • 1.提高响应速度(减少了创建新线程的时间)
  • 2.降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
  • 3.便于线程管理
  • corePoolSize:核心池的大小
  • maximumPoolSize:最大线程数
  • keepAliveTime:县城没有任何时最多保持多长时间后会终止
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class NumberThread1 implements Runnable{ @Override public void run() { for (int i=0;i<=100;i++){ if (i%2==0){ System.out.println(Thread.currentThread().getName() + ":" + i + "(run)"); } } } } class NumberThread2 implements Runnable{ @Override public void run() { for (int i=0;i<=100;i++){ if (i%2!=0){ System.out.println(Thread.currentThread().getName() + ":" + i + "(run)"); } } } } public class T01CreateThread05 { public static void main(String[] args) { //1.提供指定线程数量的线程池 ExecutorService service= Executors.newFixedThreadPool(10); //设置线程池的属性 System.out.println(service.getClass()); //执行指定的线程的操作。需要提供实现Runnable接口或者Callable接口的实现类的对象 service.execute(new NumberThread1());//适用于Runnable service.execute(new NumberThread2());//适用于Runnable //        service.submit(Callable callable);//适用于Callable //      关闭连接池 service.shutdown(); } } 

6.线程的常用方法有哪些?

start、run、setName、setPriority、setDaemon、join、yield、sleep、interrupt

本文地址:https://blog.csdn.net/weixin_43338519/article/details/107885931

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网