10 线程实现方式 execute submit

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值