A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 逆风TO 黑马粉丝团   /  2020-4-20 10:21  /  7410 人查看  /  172 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 逆风TO 于 2020-4-20 10:26 编辑

Java4种多线程的创建:
什么是程序?
什么是进程?
什么是线程?
并行与并发:
那么JAVA多线程实现方式:
(1)继承Thread类实现多线程:
(2)实现Runnable接口方式实现多线程:
(3)实现callable方式:(比实现Runnable方式强大)
(4)使用ExecutorService、Future(线程池):实现有返回结果的多线程:
线程池方式代码说明:
总结:就是4种线程的创建方式,以及简单的介绍线程。如有其他问题可以找我。
作者公众号:小白编码,欢迎大家关注一起学习。
什么是程序?
程序: 是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码。
什么是进程?
进程: 程序的一次执行过程,或是正在运行的一个程序。
说明: 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
什么是线程?
线程: 进程可进一步细化为线程 ,是一个程序内部的一条执行路径。
说明: 线程作为调度和执行的单位,每个线程拥独立的运行栈和程序计数器(pc), 线程切换的开销小。
并行与并发:
并行: 多个CPU同时执行多个任务。 如:多个人同时做不同的事情。

并发: 一个CPU(采用时间片)同时执行多个任务。 当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。这就是并发

那么JAVA多线程实现方式:
JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

(1)继承Thread类实现多线程:
继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
创建一个继承于Thread类的子类
重写Thread类的run() --> 将此线程执行的操作声明在run()中
创建Thread类的子类的对象
**通过此对象调用start() **
[Java] 纯文本查看 复制代码
public class ThreadTest extends Thread{ //创建一个继承于Thread类的子类

    //重写Thread类的run() --> 将此线程执行的操作声明在run()中
    @Override
    public void run(){
        System.out.println("这是:[" + getName() + "]的启动");
    }
    
    public static void main(String[] args) {
        //创建Thread类的子类的对象
        ThreadTest thread1 = new ThreadTest();
        ThreadTest thread2 = new ThreadTest();
        thread1.setName("线程一");//给线程设置名字
        thread2.setName("线程二");
        thread1.start();//通过线程子类对象调用start()
        thread2.start();
    }

}

控制台结果:
[Java] 纯文本查看 复制代码
这是:[线程一]的启动。
这是:[线程二]的启动。
Process finished with exit code 0
可知启动了两个线程

(2)实现Runnable接口方式实现多线程:
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口:
创建一个实现了Runnable接口的类

实现类去实现Runnable中的抽象方法:run()

创建实现类的对象

将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

通过Thread类的对象调用start()
[Java] 纯文本查看 复制代码
//创建一个实现了Runnable接口的类
public class RunnableStart extends Thread implements Runnable {
    
    //实现类去实现Runnable中的抽象方法:run()
    @Override
    public void run() {
        System.out.println("这是:[" + Thread.currentThread().getName() + "]的启动");
    }

    public static void main(String[] args) {
//        创建实现类的对象
        RunnableStart runnableThread = new RunnableStart();
//        将实现类对象作为参数传递到Thread类的构造器中,创建Thread类的对象
        Thread thread1 = new Thread(runnableThread);
        Thread thread2 = new Thread(runnableThread);
        thread1.setName("Runnable方式线程一:");//设置线程的名字
        thread2.setName("Runnable方式线程二:");
//        通过Thread类的对象调用start()
        thread1.start();
        thread2.start();
    }
}

控制台输出结果:
[Java] 纯文本查看 复制代码
这是:[Runnable方式线程二:]的启动
这是:[Runnable方式线程一:]的启动
Process finished with exit code 0

**注意点:**事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:
[Java] 纯文本查看 复制代码
public void run() {
  if (target != null) {
   target.run();
  }
}

(3)实现callable方式:(比实现Runnable方式强大)
如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?

call()可以有返回值的。
call()可以抛出异常,被外面的操作捕获,获取异常的信息
Callable是支持泛型的
创建一个实现Callable的实现类
实现call方法,将此线程需要执行的操作声明在call()中
创建Callable接口实现类的对象
将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
获取Callable中call方法的返回值

[Java] 纯文本查看 复制代码
//1.创建一个实现Callable的实现类[/b]
[b]class CallThread implements Callable {[/b]
[b]    //2.实现call方法,将此线程需要执行的操作声明在call()中[/b]
[b]    @Override[/b]
[b]    public Object call() throws Exception {[/b]
[b]        int sum = 0;[/b]
[b]        for (int i = 1; i <= 100; i++) {[/b]
[b]            if (i % 2 == 0) {[/b]
[b]                sum += i;//计算100以内偶数之和[/b]
[b]            }[/b]
[b]        }[/b]
[b]        return sum;[/b]
[b]    }[/b]
[b]}[/b]
[b]public class ThreadTest {[/b]
[b]    public static void main(String[] args) throws Exception {[/b]
[b]        //3.创建Callable接口实现类的对象[/b]
[b]        CallThread callThread = new CallThread();[/b]
[b]        //4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象[/b]
[b]        FutureTask futureTask = new FutureTask(callThread);[/b]
[b]        //5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()[/b]
[b]        Thread thread = new Thread(futureTask);[/b]
[b]        thread.start();[/b]
[b]        //6.获取Callable中call方法的返回值[/b]
[b]        //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。[/b]
[b]        Object sum = futureTask.get();[/b]
[b]        System.out.println("实现Callable方式的返回值总和为:" + sum);[/b]
[b]    }[/b]
[b]}[/b]
[b]

控制台结果:
[Java] 纯文本查看 复制代码
实现Callable方式的返回值总和为:2550[/b]
[b]Process finished with exit code 0[/b]
[b]

(4)使用ExecutorService、Future(线程池):实现有返回结果的多线程:

方法:

  • 创建一个线程池
  • 创建多个有返回值的任务
  • 执行任务并获取Future对象
  • 关闭线程池
[Java] 纯文本查看 复制代码
public class ThreadPoolTest {
    public static void main(String[] args) throws Exception {
        System.out.println("----程序开始运行----");
        Date start = new Date();//开始时间
        // 创建一个指定数量的线程池
        ExecutorService pool = Executors.newFixedThreadPool(10);
        // 创建多个有返回值的任务
        List<Future> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {//因为只设有限定10个线程
            Callable call = new TestCallable(i + " ");
            // 执行任务并获取Future对象
            Future f = pool.submit(call);
            list.add(f);
        }
        // 关闭线程池
        pool.shutdown();
        // 获取所有并发任务的运行结果
        for (Future f : list) {
            // 从Future对象上获取任务的返回值,并输出到控制台
            System.out.println(">>>" + f.get().toString());
        }
        Date end = new Date();//结束时间
        System.out.println("----程序结束运行----,程序运行时间【"
                + (end.getTime() - start.getTime()) + "毫秒】");//计算出来的总运行时间
    }
}

class TestCallable implements Callable<Object> {
    private String taskNum;//任务编号

    TestCallable(String taskNum) {
        this.taskNum = taskNum;
    }

    @Override
    public Object call() throws Exception {
        System.out.println(">>>" + taskNum + "任务启动");
        Date dateStart = new Date();//开始时间
        Thread.sleep(1000);//阻塞1000毫秒
        Date dateEnd = new Date();//结束时间
        long time = dateEnd.getTime() - dateStart.getTime();
        System.out.println(">>>" + taskNum + "任务终止");
        return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
    }
}
控制台结果:
[Java] 纯文本查看 复制代码
----程序开始运行----
>>>0 任务启动
>>>3 任务启动
>>>2 任务启动
>>>1 任务启动
>>>4 任务启动
>>>5 任务启动
>>>6 任务启动
>>>8 任务启动
>>>7 任务启动
>>>9 任务启动
>>>4 任务终止
>>>2 任务终止
>>>1 任务终止
>>>3 任务终止
>>>5 任务终止
>>>0 任务终止
>>>0 任务返回运行结果,当前任务时间【1001毫秒】
>>>1 任务返回运行结果,当前任务时间【1001毫秒】
>>>2 任务返回运行结果,当前任务时间【1001毫秒】
>>>3 任务返回运行结果,当前任务时间【1001毫秒】
>>>4 任务返回运行结果,当前任务时间【1001毫秒】
>>>5 任务返回运行结果,当前任务时间【1001毫秒】
>>>8 任务终止
>>>6 任务终止
>>>7 任务终止
>>>6 任务返回运行结果,当前任务时间【1001毫秒】
>>>7 任务返回运行结果,当前任务时间【1001毫秒】
>>>9 任务终止
>>>8 任务返回运行结果,当前任务时间【1001毫秒】
>>>9 任务返回运行结果,当前任务时间【1001毫秒】
----程序结束运行----,程序运行时间【1005毫秒】

线程池方式代码说明:
代码解释来自作者:wb_qiuquan.ying 今天莫名看到。

上述代码中Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。
public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

转自掘金:https://blog.csdn.net/weixin_46146269/article/details/105613082





172 个回复

倒序浏览
66666666666666
回复 使用道具 举报
认真学,加油加油
回复 使用道具 举报
小公举 来自手机 中级黑马 2020-5-18 14:42:48
板凳
感谢楼主的分享
回复 使用道具 举报
回复 使用道具 举报
6666666666666666
回复 使用道具 举报
66666666666666666666666
回复 使用道具 举报
6666666666666666666666666
回复 使用道具 举报
我爱我1022 来自手机 中级黑马 2020-5-18 15:34:12
9#
回复 使用道具 举报
666666666666666666666666666666
回复 使用道具 举报
4种Java多线程的创建方式
回复 使用道具 举报
加油                    
回复 使用道具 举报
我爱我1022 来自手机 中级黑马 2020-5-18 15:53:21
13#
回复 使用道具 举报
6666666666666666666
回复 使用道具 举报
你只管去努力,剩下的交给天意。
回复 使用道具 举报
加油加油加油!!!
回复 使用道具 举报
6666666666666666666666
回复 使用道具 举报
666666666666666666
回复 使用道具 举报
66666666666666666666666666
回复 使用道具 举报
666666666666666666666666666666
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马