java基础--多线程的四种创建方式

  多线程的创建方式:①继承Thread类②实现Runnable接口。第一种方式的最大局限就是不支持多继承,在JAVA中继承只能单根继承,所以为了实现多继承,可以实现Runnable接口的方式来实现。两者的创建的线程在工作时的性质是一样的。

继承Thread类

关于创建
  自定义一个MyThread,继承Thread,并且重写run方法;创建一个MyThread 类的对象,通过此对象来进行调用start()。

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("MyThread");
    }
}
public class Run {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("运行结束");
    }
}

运行结果如下,MyThread.java中的run方法执行的比较晚,说明使用多线程时,代码的运行结果与代码的执行顺序是无关的。线程是一个子任务,CPU随机执行调用线程中的run,所以就会出现先打印“运行结束”,后输出“MyThread”这样的结果。
在这里插入图片描述

  • .start()方法的作用:①启动当前线程 ②调用当前线程的 run()

两个问题:

  • 通过调用 run() 方法是不会开辟新的线程的 ,执行的线程还是 调用 run() 的线程。所以不能通过调用run() 的方式来进行启动线程
  • 在启动一个线程,不能让已经启动 start() 的线程去执行,,会报出IllegalThreadStateException错误。争取的的做法应该是在重新创建一个对象,来进行新的 start()。

关于 Thread类 的方法

  • void start(): 启动线程,并执行对象中的run() 方法
  • run() :通常徐亚重写Thread 类中的方法,将创建的线程要执行的操作声明在此方法中
  • String getName() :返回线程的名称。
  • void setName() : 设置该线程的名称。
  • static Thread currentThread() :返回当前线程。在Thread 子类中就是this,通常用于主线程和Runnable实现类。
  • yield() :线程让步,暂停当前正在执行的线程,把执行机会让给优先级相同或者更好的线程。若队列中没有同优先级的线程,忽略此方法。
  • join() :当某个程序中执流中调用了其他线程的join方法,调用线程将被阻塞,知道 join() 方法加入的 join线程执行完为止。
  • sleep() : 当前线程“睡眠”指定的millitme 毫秒 ,在指定的时间内,当前线程阻塞状态。

实现Runnab接口

关于创建
  创建线程的另外一种方式是实现Runnable接口。步骤如下
  ①创建一个实现Runnable接口的类
  ②实现类去实现Runnable中的抽象方法:run()
  ③创建实现类的对象 ,将此对象作为参数传递到Thread类中的构造器中,创建Thread类的对象
  ④通过Thread类的对象来调用start()

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("运行中");
    }
}
public class Run {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
        System.out.println("运行结束!");
    }
}

关于 Thread 和 Runnable

  • 开发中优先使用Runnable 接口中的方式
  • 原因:①实现方式没有类的单继承性的局限性②实现的方式更适合多线程有共享数据的情况。

  实际上Thread也是实现Runnable 接口的类。
在这里插入图片描述

实现Callable接口

关于创建

  1. 创建一个实现 Callable 接口的实现类
  2. 实现call() 方法,将此线程需要执行的操作声明在call方法中,允许有返回值
  3. 创建一个实现Callable接口的是实现类对象
  4. 将实现类对象作为参数传递到 FutureTask 构造器中,创建FutureTask的对象。
  5. 如果第二步没有参数,则将FutureTaskd的对象作为参数传递到Thread类构造器中,创建Tread对象,并调用start()
  6. 如果第二步返回参数(需要获取Callable中的call方法中的返回值),使用get()。get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable{

    @Override
    public Object call() throws Exception {
        int sum = 0;
        for(int i = 1;i <= 100;i++){
            if(i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}
public class Test {
    public static void main(String[] args) {
        MyCallable num = new MyCallable();

        FutureTask futureTask = new FutureTask(num);
        new Thread(futureTask).start();
        try {
            //get() 返回值为FutureTask 构造器Callable 实现类重写call的返回值
            Object o = futureTask.get();
            System.out.println(o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

实现Runnable 和实现Callable

  • call() 可以有返回值
  • call()还可以跑出异常,被外面的操作捕获,接收异常的信息。
  • 可以支持泛型

使用线程池

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中,可以避免频繁创建销毁,实现重复利用。

好处:

  • 提高响应速度(减少了创建新线程的时间)
  • 降低资源消耗(重复利用线程池中的线程,不需要每次都进行创建)
  • 便于线程管理
    - corePoolSize:核心池中的大小
    - maximumPoolSize:最大的线程数
    - keepAliveTime: 线程没有任务时最多保持多长时间会终止

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class MyRunnable implements Runnable {
    @Override
    public void run() {
        for(int i = 1;i <= 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }}
}
class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 1;
        for(int i = 1;i <= 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName()+i);
                sum += i;
            }
        }
        return sum;
    }
}
public class Pool {
    public static void main(String[] args) {
        //1.提供指定线程数量的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        //2.执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
        //service.execute(new MyRunnable());//适合适用于Runnable
        service.submit(new MyCallable());//适合使用与Callable
        //3.关闭线程池
        service.shutdown();
    }
}

有关于线程池的API ExextorService 和 Exectors

  • ExextorService :真正的线程池接口,常见的子类有ThreadPoolExecutor
    - void execute(Runnable command):执行任务/命令,没有返回值,易班用来执行Runnable
    - Future submit (Callable task) :执行任务,有返回值,一般用来执行Callable
    - void shutdown :关闭连接池
  • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
    - Executors.newCachedThreadPool():创建一个课根据需要创建新线程的线程池
    - Executors.newFixedThreadddPool():创建一个可重用固定线程数的线程池
    - Executors.newSingleThreadExecutor():创建一个只有一个线程的线程池
    - Executors.newScheduledThreadPool(n):创建一个线程池,它可以安排在给定延迟后运行命令或者定期的执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值