编程语言
首页 > 编程语言> > JAVA进阶--多线程、定时器、并发并行、线程的生命周期--2022年9月8日

JAVA进阶--多线程、定时器、并发并行、线程的生命周期--2022年9月8日

作者:互联网

第一节、多线程的创建

  1、线程概述

    A、什么是线程

    

 

     B、多线程是什么

    

  2、继承Thread类

    A、继承Thread类是如何实现多线程的

      继承Thread类

      重写run方法

      创建线程对象

      调用start()方法启动

    B、优缺点是什么

      优点:编码简单

      缺点:存在单继承的局限性,线程类继承Thread后,不能继承其他类,不便于扩展。

    C、为什么不直接调用run()方法,而是调用start()启动线程

      直接调用run方法会当次普通方法执行,此时相当于还是单线程执行

      只有调用start方法才是启动一个新的线程执行

    D、把主线程任务放在子线程之前会怎么样

      这样主线程一直是先跑完,相当于是一个线程的效果了

    

 1 package com.itheima.d1_create;
 2 
 3 /**
 4    目标:多线程的创建方式一:继承Thread类实现。
 5  */
 6 public class ThreadDemo1 {
 7     public static void main(String[] args) {
 8         // 3、new一个新线程对象
 9         Thread t = new MyThread();
10         // 4、调用start方法启动线程(执行的还是run方法)
11         t.start();
12 
13         for (int i = 0; i < 5; i++) {
14             System.out.println("主线程执行输出:" + i);
15         }
16 
17     }
18 }
19 
20 /**
21    1、定义一个线程类继承Thread类
22  */
23 class MyThread extends Thread{
24     /**
25        2、重写run方法,里面是定义线程以后要干啥
26      */
27     @Override
28     public void run() {
29         for (int i = 0; i < 5; i++) {
30             System.out.println("子线程执行输出:" + i);
31         }
32     }
33 }
继承thread类创建线程

  3、实现Runnable接口

    A。实现Uunnable接口是如何创建线程的

      定义一个线程任务类型MyRunnable实现Runnable接口,重写run()方法

      创建MyRunnable任务对象

      把MyRunnable任务对象交给Thread线程对象处理

      调用线程对象的start()方法启动线程

    B、这种方式的优缺点

      优点:线程任务只是实现了Runnable接口,可以继续继承和实现

      缺点:编程多一层包装对象,如果线程有执行结果是不能直接返回的

    

 1 package com.itheima.d1_create;
 2 
 3 /**
 4    目标:学会线程的创建方式二,理解它的优缺点。
 5  */
 6 public class ThreadDemo2 {
 7     public static void main(String[] args) {
 8         // 3、创建一个任务对象
 9         Runnable target = new MyRunnable();
10         // 4、把任务对象交给Thread处理
11         Thread t = new Thread(target);
12         // Thread t = new Thread(target, "1号");
13         // 5、启动线程
14         t.start();
15 
16         for (int i = 0; i < 10; i++) {
17             System.out.println("主线程执行输出:" + i);
18         }
19     }
20 }
21 
22 /**
23    1、定义一个线程任务类 实现Runnable接口
24  */
25 class MyRunnable  implements Runnable {
26     /**
27        2、重写run方法,定义线程的执行任务的
28      */
29     @Override
30     public void run() {
31         for (int i = 0; i < 10; i++) {
32             System.out.println("子线程执行输出:" + i);
33         }
34     }
35 }
实现Runnable接口

     =============================================================================================

    

 1 package com.itheima.d1_create;
 2 
 3 /**
 4    目标:学会线程的创建方式二(匿名内部类方式实现,语法形式)
 5  */
 6 public class ThreadDemo2Other {
 7     public static void main(String[] args) {
 8         Runnable target = new Runnable() {
 9             @Override
10             public void run() {
11                 for (int i = 0; i < 10; i++) {
12                     System.out.println("子线程1执行输出:" + i);
13                 }
14             }
15         };
16         Thread t = new Thread(target);
17         t.start();
18 
19         new Thread(new Runnable() {
20             @Override
21             public void run() {
22                 for (int i = 0; i < 10; i++) {
23                     System.out.println("子线程2执行输出:" + i);
24                 }
25             }
26         }).start();
27 
28         new Thread(() -> {
29                 for (int i = 0; i < 10; i++) {
30                     System.out.println("子线程3执行输出:" + i);
31             }
32         }).start();
33 
34         for (int i = 0; i < 10; i++) {
35             System.out.println("主线程执行输出:" + i);
36         }
37     }
38 }
实现Runnable接口-匿名对象类

  4、JDK5.0新增:实现Callable接口

    A、利用Callable、FutureTask接口实现的步骤

      得到任务对象

        定义类实现Callable接口,重写call方法,封装要做的事情

        用FutureTask把Callable对象封装成线程任务对象

      把线程任务对象交给Thread处理

      调用Thread的start方法启动线程,执行任务

      线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果

    

 

 

     ==============================================================================

    

 

 

     ===============================================================================================

    

 1 package com.itheima.d1_create;
 2 
 3 import java.util.concurrent.Callable;
 4 import java.util.concurrent.ExecutionException;
 5 import java.util.concurrent.FutureTask;
 6 
 7 /**
 8    目标:学会线程的创建方式三:实现Callable接口,结合FutureTask完成。
 9  */
10 public class ThreadDemo3 {
11     public static void main(String[] args) {
12         // 3、创建Callable任务对象
13         Callable<String> call = new MyCallable(100);
14         // 4、把Callable任务对象 交给 FutureTask 对象
15         //  FutureTask对象的作用1: 是Runnable的对象(实现了Runnable接口),可以交给Thread了
16         //  FutureTask对象的作用2: 可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果
17         FutureTask<String> f1 = new FutureTask<>(call);
18         // 5、交给线程处理
19         Thread t1 = new Thread(f1);
20         // 6、启动线程
21         t1.start();
22 
23 
24         Callable<String> call2 = new MyCallable(200);
25         FutureTask<String> f2 = new FutureTask<>(call2);
26         Thread t2 = new Thread(f2);
27         t2.start();
28 
29         try {
30             // 如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果。
31             String rs1 = f1.get();
32             System.out.println("第一个结果:" + rs1);
33         } catch (Exception e) {
34             e.printStackTrace();
35         }
36 
37         try {
38             // 如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才提取结果。
39             String rs2 = f2.get();
40             System.out.println("第二个结果:" + rs2);
41         } catch (Exception e) {
42             e.printStackTrace();
43         }
44     }
45 }
46 
47 /**
48     1、定义一个任务类 实现Callable接口  应该申明线程任务执行完毕后的结果的数据类型
49  */
50 class MyCallable implements Callable<String>{
51     private int n;
52     public MyCallable(int n) {
53         this.n = n;
54     }
55 
56     /**
57        2、重写call方法(任务方法)
58      */
59     @Override
60     public String call() throws Exception {
61         int sum = 0;
62         for (int i = 1; i <= n ; i++) {
63             sum += i;
64         }
65         return "子线程执行的结果是:" + sum;
66     }
67 }
第三种线程创建方式

第二节、Thread的常用方法

  1、Thread常用API

     

  2、Thread构造器

    

 1 package com.itheima.d2_api;
 2 
 3 public class MyThread extends Thread{
 4     public MyThread() {
 5     }
 6 
 7     public MyThread(String name) {
 8         // 为当前线程对象设置名称,送给父类的有参数构造器初始化名称
 9         super(name);
10     }
11 
12     @Override
13     public void run() {
14         for (int i = 0; i < 5; i++) {
15             System.out.println( Thread.currentThread().getName() + "输出:" + i);
16         }
17     }
18 }
为线程对象设置名称
 1 package com.itheima.d2_api;
 2 /**
 3     目标:线程的API
 4  */
 5 public class ThreadDemo01 {
 6     // main方法是由主线程负责调度的
 7     public static void main(String[] args) {
 8         Thread t1 = new MyThread("1号");
 9         // t1.setName("1号");
10         t1.start();
11         System.out.println(t1.getName());
12 
13         Thread t2 = new MyThread("2号");
14         // t2.setName("2号");
15         t2.start();
16         System.out.println(t2.getName());
17 
18         // 哪个线程执行它,它就得到哪个线程对象(当前线程对象)
19         // 主线程的名称就叫main
20         Thread m = Thread.currentThread();
21         System.out.println(m.getName());
22         m.setName("最牛的线程");
23 
24         for (int i = 0; i < 5; i++) {
25             System.out.println( m.getName() + "输出:" + i);
26         }
27     }
28 }
依然是名称
 1 package com.itheima.d2_api;
 2 /**
 3     目标:线程的API
 4  */
 5 public class ThreadDemo02 {
 6     // main方法是由主线程负责调度的
 7     public static void main(String[] args) throws Exception {
 8         for (int i = 1; i <= 5; i++) {
 9             System.out.println("输出:" + i);
10             if(i == 3){
11                 // 让当前线程进入休眠状态
12                 // 段子:项目经理让我加上这行代码,如果用户愿意交钱,我就注释掉。
13                 Thread.sleep(3000);
14             }
15         }
16     }
17 }
线程休眠

第三节、线程安全

  1、线程安全问题是什么

    多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题

  2、线程安全问题出现的原因

    存在多线程并发

    同时访问共享资源

    存在修改共享资源,读数据是永远不会错的,只有需要修改的时候才会出错

  3、线程安全问题案例模拟

    

 1 package com.itheima.d3_thread_safe;
 2 
 3 public class Account {
 4     private String cardId;
 5     private double money; // 账户的余额
 6 
 7     public Account(){
 8 
 9     }
10 
11     public Account(String cardId, double money) {
12         this.cardId = cardId;
13         this.money = money;
14     }
15 
16     /**
17        小明 小红
18      */
19     public void drawMoney(double money) {
20         // 0、先获取是谁来取钱,线程的名字就是人名
21         String name = Thread.currentThread().getName();
22         // 1、判断账户是否够钱
23         if(this.money >= money){
24             // 2、取钱
25             System.out.println(name + "来取钱成功,吐出:" + money);
26             // 3、更新余额
27             this.money -= money;
28             System.out.println(name + "取钱后剩余:" + this.money);
29         }else {
30             // 4、余额不足
31             System.out.println(name +"来取钱,余额不足!");
32         }
33 
34     }
35 
36     public String getCardId() {
37         return cardId;
38     }
39 
40     public void setCardId(String cardId) {
41         this.cardId = cardId;
42     }
43 
44     public double getMoney() {
45         return money;
46     }
47 
48     public void setMoney(double money) {
49         this.money = money;
50     }
51 
52 }
Account类
 1 package com.itheima.d3_thread_safe;
 2 
 3 /**
 4    取钱的线程类
 5  */
 6 public class DrawThread extends Thread {
 7     // 接收处理的账户对象
 8     private Account acc;
 9     public DrawThread(Account acc,String name){
10         super(name);
11         this.acc = acc;
12     }
13     @Override
14     public void run() {
15         // 小明 小红:取钱
16         acc.drawMoney(100000);
17     }
18 }
DrawThread
 1 package com.itheima.d3_thread_safe;
 2 
 3 /**
 4     需求:模拟取钱案例。
 5  */
 6 public class ThreadDemo {
 7     public static void main(String[] args) {
 8         // 1、定义线程类,创建一个共享的账户对象
 9         Account acc = new Account("ICBC-111", 100000);
10 
11         // 2、创建2个线程对象,代表小明和小红同时进来了。
12         new DrawThread(acc, "小明").start();
13         new DrawThread(acc, "小红").start();
14     }
15 }
ThreadDemo 启动类

第四节、线程同步

  1、同步思想概述

    A、线程同步解决安全问题的思想是什么

      加锁:让多个线程实现先后依次访问共享资源,这样就解决了安全问题

  2、方式一、同步代码块

    A、同步代码块是如何实现线程安全的

      对出现问题的核心代码使用synchronized进行加锁

      每次只能一个线程占锁进入访问

    B、同步代码块的同步锁对象有什么要求

      对于实例方法建议使用this作为锁对象

      对于静态方法建议使用字节码(类名.class)对象作为锁对象

    

 

 

     ========================================================================

    

  3、方式二、同步方法

    A、同步方法是如何保证线程安全的

      对出现问题的核心方法使用synchronized修饰

      每次只能一个线程占锁进入访问

    B、同步方法的同步锁对象的原理

      对于实例方法默认使用this作为锁对象

      对于静态方法默认使用类名.class对象作为锁对象

    C、同步代码块和同步方法的比较

      同步代码块锁的范围更小,同步方法锁的范围更大

      在书写代码上面,同步方法比同步代码块更方便一点

    

 

 

     ==========================================================================

    

  4、方式三、Lock锁

    

第五节、线程通信

  1、线程通信的三个常见方法

  

 

 

   =======================================================================

  

 1 package com.itheima.d7_thread_comunication;
 2 
 3 /**
 4    呼叫系统。
 5  */
 6 public class CallSystem {
 7     // 定义一个变量记录当前呼入进来的电话。
 8     public static int number = 0; // 最多只接听一个。
 9 
10     /* 接入电话
11      */
12     public synchronized static void call() {
13         try {
14             number++;
15             System.out.println("成功接入一个用户,等待分发~~~~");
16 
17             // 唤醒别人 : 1个
18             CallSystem.class.notify();
19             // 让当前线程对象进入等待状态。
20             CallSystem.class.wait();
21 
22         } catch (InterruptedException e) {
23             e.printStackTrace();
24         }
25     }
26 
27     /**
28        分发电话
29      */
30     public synchronized static void receive() {
31         try {
32             String name = Thread.currentThread().getName();
33             if(number == 1){
34                 System.out.println(name + "此电话已经分发给客服并接听完毕了~~~~~");
35                 number--;
36                 // 唤醒别人 : 1个
37                 CallSystem.class.notify();
38                 CallSystem.class.wait(); // 让当前线程等待
39             }else {
40                 // 唤醒别人 : 1个
41                 CallSystem.class.notify();
42                 CallSystem.class.wait(); // 让当前线程等待
43             }
44         } catch (InterruptedException e) {
45             e.printStackTrace();
46         }
47     }
48 }
线程通信案例CallSystem
 1 package com.itheima.d7_thread_comunication;
 2 
 3 public class CallThread extends Thread{
 4     @Override
 5     public void run() {
 6         // 不断的打入电话
 7         while (true){
 8             CallSystem.call();
 9         }
10     }
11 }
线程通信案例 CallThread
 1 package com.itheima.d7_thread_comunication;
 2 
 3 /**
 4    接电话线程类
 5  */
 6 public class ReceiveThread extends Thread{
 7     @Override
 8     public void run() {
 9         // 1号  2号
10         while (true){
11             CallSystem.receive();
12         }
13     }
14 }
线程通信案例 ReceiveThread
 1 package com.itheima.d7_thread_comunication;
 2 
 3 public class TestDemo {
 4     public static void main(String[] args) {
 5         // 1、生产者线程:负责不断接收打进来的电话
 6         CallThread call = new CallThread();
 7         call.start();
 8 
 9         // 2、消费者线程:客服,每个客服每次接听一个电话
10         ReceiveThread r1 = new ReceiveThread();
11         r1.start();
12     }
13 }
线程通信案例 TestDemo

第六节、线程池

  1、线程池概述

    

 

 

     ===============================================================================================

    

  2、线程池实现的API、参数说明

    A、谁代表了线程池

      ExecutorService接口

      

    B、ThreadPoolExecutor实现线程池对象的七个参数是什么意思

      使用线程池的实现类ThreadPoolExecutor

      

 

     C、线程池常见面试题

      a、临时线程什么时候创建

        新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程

      b、什么时候会开始拒绝任务

        核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝

  3、线程池处理Runnable任务

    A、线程池如何处理Runnable任务

      使用ExecutorService的方法:void execute(Runnable target)

    

 

     =====================================================================================================

    

  4、线程池处理Callable任务

    A、线程池如何处理Callable任务,并得到任务执行完后返回结果

      使用ExecutorService的方法:Future<T>submit(Callable<T>command)

 1 package com.itheima.d8_threadpool;
 2 
 3 import java.util.concurrent.Callable;
 4 
 5 /**
 6     1、定义一个任务类 实现Callable接口  应该申明线程任务执行完毕后的结果的数据类型
 7  */
 8 public class MyCallable implements Callable<String>{
 9     private int n;
10     public MyCallable(int n) {
11         this.n = n;
12     }
13 
14     /**
15        2、重写call方法(任务方法)
16      */
17     @Override
18     public String call() throws Exception {
19         int sum = 0;
20         for (int i = 1; i <= n ; i++) {
21             sum += i;
22         }
23         return Thread.currentThread().getName()
24                 + "执行 1-" + n+ "的和,结果是:" + sum;
25     }
26 }
MyCallable
 1 package com.itheima.d8_threadpool;
 2 
 3 public class MyRunnable implements Runnable{
 4     @Override
 5     public void run() {
 6         for (int i = 0; i < 5; i++) {
 7             System.out.println(Thread.currentThread().getName() + "输出了:HelloWorld ==> "  + i);
 8         }
 9         try {
10             System.out.println(Thread.currentThread().getName() + "本任务与线程绑定了,线程进入休眠了~~~");
11             Thread.sleep(10000000);
12         } catch (Exception e) {
13             e.printStackTrace();
14         }
15     }
16 }
MyRunnable
 1 package com.itheima.d8_threadpool;
 2 
 3 import java.util.concurrent.*;
 4 
 5 /**
 6     目标:自定义一个线程池对象,并测试其特性。
 7  */
 8 public class ThreadPoolDemo1 {
 9     public static void main(String[] args) {
10         // 1、创建线程池对象
11         /**
12          public ThreadPoolExecutor(int corePoolSize,
13                                  int maximumPoolSize,
14                                  long keepAliveTime,
15                                  TimeUnit unit,
16                                  BlockingQueue<Runnable> workQueue,
17                                  ThreadFactory threadFactory,
18                                  RejectedExecutionHandler handler)
19          */
20         ExecutorService pool = new ThreadPoolExecutor(3, 5 ,
21                 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(),
22                new ThreadPoolExecutor.AbortPolicy() );
23 
24         // 2、给任务线程池处理。
25         Runnable target = new MyRunnable();
26         pool.execute(target);
27         pool.execute(target);
28         pool.execute(target);
29 
30         pool.execute(target);
31         pool.execute(target);
32         pool.execute(target);
33         pool.execute(target);
34         pool.execute(target);
35 
36         // 创建临时线程
37         pool.execute(target);
38         pool.execute(target);
39 //        // 不创建,拒绝策略被触发!!!
40 //        pool.execute(target);
41 
42         // 关闭线程池(开发中一般不会使用)。
43         // pool.shutdownNow(); // 立即关闭,即使任务没有完成,会丢失任务的!
44         pool.shutdown(); // 会等待全部任务执行完毕之后再关闭(建议使用的)
45     }
46 }
ThreadPoolDemo1
 1 package com.itheima.d8_threadpool;
 2 
 3 import java.util.concurrent.*;
 4 
 5 /**
 6     目标:自定义一个线程池对象,并测试其特性。
 7  */
 8 public class ThreadPoolDemo2 {
 9     public static void main(String[] args) throws Exception {
10         // 1、创建线程池对象
11         /**
12          public ThreadPoolExecutor(int corePoolSize,
13                                  int maximumPoolSize,
14                                  long keepAliveTime,
15                                  TimeUnit unit,
16                                  BlockingQueue<Runnable> workQueue,
17                                  ThreadFactory threadFactory,
18                                  RejectedExecutionHandler handler)
19          */
20         ExecutorService pool = new ThreadPoolExecutor(3, 5 ,
21                 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(),
22                new ThreadPoolExecutor.AbortPolicy() );
23 
24         // 2、给任务线程池处理。
25         Future<String> f1 = pool.submit(new MyCallable(100));
26         Future<String> f2 = pool.submit(new MyCallable(200));
27         Future<String> f3 = pool.submit(new MyCallable(300));
28         Future<String> f4 = pool.submit(new MyCallable(400));
29         Future<String> f5 = pool.submit(new MyCallable(500));
30 
31 //        String rs = f1.get();
32 //        System.out.println(rs);
33 
34         System.out.println(f1.get());
35         System.out.println(f2.get());
36         System.out.println(f3.get());
37         System.out.println(f4.get());
38         System.out.println(f5.get());
39     }
40 }
ThreadPoolDemo2
 1 package com.itheima.d8_threadpool;
 2 
 3 import java.util.concurrent.*;
 4 
 5 /**
 6     目标:使用Executors的工具方法直接得到一个线程池对象。
 7  */
 8 public class ThreadPoolDemo3 {
 9     public static void main(String[] args) throws Exception {
10         // 1、创建固定线程数据的线程池
11         ExecutorService pool = Executors.newFixedThreadPool(3);
12 
13         pool.execute(new MyRunnable());
14         pool.execute(new MyRunnable());
15         pool.execute(new MyRunnable());
16         pool.execute(new MyRunnable()); // 已经没有多余线程了
17     }
18 }
ThreadPoolDemo3

  5、Executors工具类实现线程池

    A、Executor工具类底层是基于什么方式实现的线程池对象

      线程池ExecutorService的实现类:ThreadPoolExecutor

    B、Executor是否适合做大型互联网场景的线程池方案

      不适合

      建议使用ThreadPoolExecutor来指定线程池参数,这样可以明确线程池的运行规则,规避资源耗尽的风险

    

 

     ==========================================================================================================

    

 

     ===========================================================================================================

    

第七节、补充知识:定时器

  1、定时器是什么,它的作用是什么

    定时器是一种控制任务延时调用,或者周期调用的技术

    作用:闹钟、定时邮件发送

  2、定时器的实现方式

    方式一:Timer

    方式二:ScheduledExecutorService

  

 1 package com.itheima.d9_timer;
 2 
 3 import java.util.Date;
 4 import java.util.Timer;
 5 import java.util.TimerTask;
 6 
 7 /**
 8     目标:Timer定时器的使用和了解。
 9  */
10 public class TimerDemo1 {
11     public static void main(String[] args) {
12         // 1、创建Timer定时器
13         Timer timer = new Timer();  // 定时器本身就是一个单线程。
14         // 2、调用方法,处理定时任务
15         timer.schedule(new TimerTask() {
16             @Override
17             public void run() {
18                 System.out.println(Thread.currentThread().getName() + "执行AAA~~~" + new Date());
19 //                try {
20 //                    Thread.sleep(5000);
21 //                } catch (InterruptedException e) {
22 //                    e.printStackTrace();
23 //                }
24             }
25         }, 0, 2000);
26 
27         timer.schedule(new TimerTask() {
28             @Override
29             public void run() {
30                 System.out.println(Thread.currentThread().getName() + "执行BB~~~"+ new Date());
31                 System.out.println(10/0);
32             }
33         }, 0, 2000);
34 
35         timer.schedule(new TimerTask() {
36             @Override
37             public void run() {
38                 System.out.println(Thread.currentThread().getName() + "执行CCC~~~"+ new Date());
39             }
40         }, 0, 3000);
41     }
42 }
Timer

  

 1 package com.itheima.d9_timer;
 2 
 3 import java.util.Date;
 4 import java.util.Timer;
 5 import java.util.TimerTask;
 6 import java.util.concurrent.Executors;
 7 import java.util.concurrent.ScheduledExecutorService;
 8 import java.util.concurrent.TimeUnit;
 9 
10 /**
11     目标:Timer定时器的使用和了解。
12  */
13 public class TimerDemo2 {
14     public static void main(String[] args) {
15         // 1、创建ScheduledExecutorService线程池,做定时器
16         ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
17 
18         // 2、开启定时任务
19         pool.scheduleAtFixedRate(new TimerTask() {
20             @Override
21             public void run() {
22                 System.out.println(Thread.currentThread().getName() + "执行输出:AAA  ==》 " + new Date());
23                 try {
24                     Thread.sleep(100000);
25                 } catch (InterruptedException e) {
26                     e.printStackTrace();
27                 }
28             }
29         }, 0, 2, TimeUnit.SECONDS);
30 
31 
32         pool.scheduleAtFixedRate(new TimerTask() {
33             @Override
34             public void run() {
35                 System.out.println(Thread.currentThread().getName() + "执行输出:BBB  ==》 " + new Date());
36                 System.out.println(10 / 0);
37             }
38         }, 0, 2, TimeUnit.SECONDS);
39 
40 
41         pool.scheduleAtFixedRate(new TimerTask() {
42             @Override
43             public void run() {
44                 System.out.println(Thread.currentThread().getName() + "执行输出:CCC  ==》 " + new Date());
45             }
46         }, 0, 2, TimeUnit.SECONDS);
47 
48     }
49 }
ScheduledExecutorService

第八节、补充知识:并发、并行

  1、简单说说并发和并行的含义

    并发:CPU分时轮询的执行线程

    并行:同一个时刻同时在执行

  

 

   =======================================================================================================

  

第九节、补充知识:线程的生命周期

  1、线程的6种状态

     

 

       ==================================================================================================

      

 

标签:JAVA,Thread,--,线程,println,new,多线程,public,out
来源: https://www.cnblogs.com/Flower--Dance/p/16666882.html