java中线程实现方式(execute和submit方式的区别)
程序员文章站
2024-01-11 16:29:34
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
上一篇: 记一次生产问题