目录
一.多线程的创建
1.方式一:继承Thread类
package com.wjh.d1_create;
/*
目标:多线程的创建方式之一:继承Thread类实现
*/
public class ThreadDemo1 {
public static void main(String[] args) {
//3.new一个新线程对象
Thread t = new MyThread();
//4.调用start方法启动线程(执行的还是run方法)
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("主线程执行输出:" + i);
}
}
}
/*
1.定义一个线程类继承Thread类
*/
class MyThread extends Thread{
/*
2.重写run方法,里面是定义线程以后要做的事情
*/
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程执行输出:" + i);
}
}
}
子线程执行输出:0
主线程执行输出:0
主线程执行输出:1
主线程执行输出:2
主线程执行输出:3
主线程执行输出:4
子线程执行输出:1
子线程执行输出:2
子线程执行输出:3
子线程执行输出:4进程已结束,退出代码为 0
2.方式二:实现Runnable接口
package com.wjh.d1_create;
/*
目标:学会线程的创建方式二:理解他的优缺点.
*/
public class ThreadDemo2 {
public static void main(String[] args) {
//3.创建一个任务对象
Runnable runnable = new MyRunnable();
//4.把任务对象交给Thread处理
Thread t =new Thread(runnable);
//5.启动线程
t.start();
//主线程任务:
for (int i = 0; i < 10; i++) {
System.out.println("主线程执行输出:" + i);
}
}
}
/*
定义一个线程任务类 实现Runnable接口
*/
class MyRunnable extends Object implements Runnable{
/*
2.重写run方法,定义线程的执行任务
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程执行输出:" + i);
}
}
}
主线程执行输出:0
主线程执行输出:1
子线程执行输出:0
主线程执行输出:2
子线程执行输出:1
主线程执行输出:3
子线程执行输出:2
主线程执行输出:4
子线程执行输出:3
主线程执行输出:5
主线程执行输出:6
子线程执行输出:4
主线程执行输出:7
子线程执行输出:5
子线程执行输出:6
子线程执行输出:7
子线程执行输出:8
主线程执行输出:8
子线程执行输出:9
主线程执行输出:9进程已结束,退出代码为 0
package com.wjh.d1_create;
/*
目标:学会线程的创建方式二:(匿名内部类方法实现,语句形式)
*/
public class ThreadDemo2_Other {
public static void main(String[] args) {
//3.创建一个任务对象(匿名内部类)
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程1执行输出:" + i);
}
}
};
//4.把任务对象交给Thread处理
Thread t =new Thread(runnable);
//5.启动线程
t.start();
//简化写法1
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程2执行输出:" + i);
}
}
}).start();
//简化写法2
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("子线程3执行输出:" + i);
}
}).start();
//主线程任务:
for (int i = 0; i < 10; i++) {
System.out.println("主线程执行输出:" + i);
}
}
}
子线程3执行输出:0
主线程执行输出:0
子线程2执行输出:0
子线程2执行输出:1
子线程1执行输出:0
子线程2执行输出:2
子线程1执行输出:1
主线程执行输出:1
子线程3执行输出:1
主线程执行输出:2
主线程执行输出:3
子线程1执行输出:2
子线程1执行输出:3
子线程1执行输出:4
子线程2执行输出:3
子线程1执行输出:5
子线程2执行输出:4
子线程2执行输出:5
主线程执行输出:4
主线程执行输出:5
主线程执行输出:6
主线程执行输出:7
主线程执行输出:8
主线程执行输出:9
子线程3执行输出:2
子线程2执行输出:6
子线程1执行输出:6
子线程1执行输出:7
子线程1执行输出:8
子线程1执行输出:9
子线程2执行输出:7
子线程2执行输出:8
子线程2执行输出:9
子线程3执行输出:3
子线程3执行输出:4
子线程3执行输出:5
子线程3执行输出:6
子线程3执行输出:7
子线程3执行输出:8
子线程3执行输出:9进程已结束,退出代码为 0
3.方式三:JDK 5.0新增:实现Callable接口
package com.wjh.d1_create;
/*
目标:多线程的创建方式之三:实现Callable接口,结合FutureTask完成.
*/
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo3 {
public static void main(String[] args) {
//3.创建Callable任务对象
Callable<String> call1 = new MyCallable(100); //传参
//4.把callable任务对象交给FutureTask对象
//FutureTask对象的作用1:是Runnable对象(实现了Runnable接口),可以交给Thread了
//FutureTask对象的作用2:可以在线程执行完毕之后调用其get方法得到线程执行完成的结果
FutureTask<String> f1 = new FutureTask<>(call1);
//5.交给线程处理
Thread t1 = new Thread(f1);
//6.启动线程
t1.start();
//=====================================================================
//3.创建Callable任务对象
Callable<String> call2 = new MyCallable(200); //传参
//4.把callable任务对象交给FutureTask对象
//FutureTask对象的作用1:是Runnable对象(实现了Runnable接口),可以交给Thread了
//FutureTask对象的作用2:可以在线程执行完毕之后调用其get方法得到线程执行完成的结果
FutureTask<String> f2 = new FutureTask<>(call2);
//5.交给线程处理
Thread t2 = new Thread(f2);
//6.启动线程
t2.start();
//=====================================================================
try {
//如果f1没有执行完毕!,这里的代码会等待,知道线程1跑完才提取结果.
String rs1 = f1.get();
System.out.println("第一个结果:" + rs1);
} catch (Exception e) {
e.printStackTrace();
}
try {
String rs2 = f2.get();
System.out.println("第二个结果:" + rs2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
定义一个任务类,实现Callable接口 必须申明线程任务执行完毕后的结果的数据类型
*/
class MyCallable implements Callable<String>{ //<String> -> 返回
private int n;
public MyCallable(int n) {
this.n = n;
}
/*
重写call方法(线程的任务方法)
*/
@Override
public String call() throws Exception {
int count = 0;
for (int i = 1; i <= n; i++) {
count += i;
}
return "子线程执行的结果是:" + count;
}
}
第一个结果:子线程执行的结果是:5050
第二个结果:子线程执行的结果是:20100进程已结束,退出代码为 0
二.Thread的常用方法
package com.wjh.d2_api;
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
//为当前对象设置名称
super(name);
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "线程输出:" + i);
//默认名字 Thread-1 / Thread-0
}
}
}
package com.wjh.d2_api;
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t1 = new MyThread("1号");
//t1.setName("1号");
t1.start();
System.out.println(t1.getName());
Thread t2 = new MyThread("2号");
//t2.setName("2号");
t2.start();
System.out.println(t2.getName());
//哪个线程执行它,它就得到哪个线程对象(当前线程对象)
//主线程的名称就叫main
Thread m = Thread.currentThread();
System.out.println(m.getName());
m.setName("最牛");
for (int i = 0; i < 5; i++) {
System.out.println(m.getName() + "线程输出:" + i);
}
}
}
1号
2号
main
最牛线程输出:0
最牛线程输出:1
最牛线程输出:2
最牛线程输出:3
最牛线程输出:4
1号线程输出:0
1号线程输出:1
1号线程输出:2
1号线程输出:3
1号线程输出:4
2号线程输出:0
2号线程输出:1
2号线程输出:2
2号线程输出:3
2号线程输出:4进程已结束,退出代码为 0
package com.wjh.d2_api;
/*
目标:线程的API
*/
public class ThreadDemo2 {
//main方法就是由主线程负责调度的
public static void main(String[] args) throws Exception{
for (int i = 1; i <= 5 ; i++) {
System.out.println("输出:" + i);
if(i == 3){
//让线程进入休眠状态
//段子:项目经理让加,如果愿意交钱,就注释掉
Thread.sleep(3000); //单位毫秒
}
}
}
}
输出:1
输出:2
输出:3
输出:4
输出:5进程已结束,退出代码为 0
//4.把任务对象交给Thread处理
Thread t =new Thread(runnable, "1号");
三.线程安全
1.线程安全问题是什么,发生的原因
2.线程安全模拟
账户类:
package com.wjh.d3_thread_saft;
//账户类
public class Account {
private String cardId;
private double money;
public Account() {
}
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
/**
* 小明 小红
* @param money
*/
public void drawMoney(double money) {
//先获取是谁来取钱
String name = Thread.currentThread().getName();
//1.判断账户余额是否足够
if (this.money >= money){
//2.取钱
System.out.println(name + "来取钱,取走:" + money);
//3.更新余额
this.money -= money;
System.out.println(name + "来取钱,剩余余额:" + this.money);
}else{
System.out.println(name + "来取钱,余额不足!");
}
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
线程类:
package com.wjh.d3_thread_saft;
/*
取钱的线程类
*/
public class DrawThead extends Thread{
private Account acc;
public DrawThead(Account acc,String name) {
super(name);
this.acc = acc;
}
@Override
public void run() {
// 小明/小红:取钱
acc.drawMoney(100000);
}
}
测试类:
package com.wjh.d3_thread_saft;
/*
需求:
小明和小红是一对夫妻,他们有一个共同的账户,余额是10万元,模拟2人同时去取钱10万。
分析:
①:需要提供一个账户类,创建一个账户对象代表2个人的共享账户。
②:需要定义一个线程类,线程类可以处理账户对象。
③:创建2个线程对象,传入同一个账户对象。
④:启动2个线程,去同一个账户对象中取钱10万。
*/
public class ThreadDemo1 {
public static void main(String[] args) {
//1.定义一个账户类对象,创建一个共享账户
Account acc = new Account("622682",100000);
//2.开始创建2个线程对象,代表小明和小红同时进来了
new DrawThead(acc, "小明").start();
new DrawThead(acc, "小红").start();
}
}
小红来取钱,取走:100000.0
小明来取钱,取走:100000.0
小红来取钱,剩余余额:0.0
小明来取钱,剩余余额:-100000.0进程已结束,退出代码为 0
(出现了线程安全问题)
四.线程同步
1.同步思想概述
2.方法一:同步代码块
//同步代码块(小明- 小红) : Ctrl + Alt + t
synchronized ("wjh") {
//1.判断账户余额是否足够
if (this.money >= money){
//2.取钱
System.out.println(name + "来取钱,取走:" + money);
//3.更新余额
this.money -= money;
System.out.println(name + "来取钱,剩余余额:" + this.money);
}else{
System.out.println(name + "来取钱,余额不足!");
}
}
// //加入100个线程调用
// public static void run(){
// synchronized (Account.class){
//
// }
// }
3.方法二:同步方法
/**
* 小明 小红
* @param money
*/
public synchronized void drawMoney(double money) {
//先获取是谁来取钱
String name = Thread.currentThread().getName();
//同步代码块(小明- 小红) : Ctrl + Alt + t
//操作同一个账户 (this) == acc
//1.判断账户余额是否足够
if (this.money >= money){
//2.取钱
System.out.println(name + "来取钱,取走:" + money);
//3.更新余额
this.money -= money;
System.out.println(name + "来取钱,剩余余额:" + this.money);
}else{
System.out.println(name + "来取钱,余额不足!");
}
}
3.Lock锁
//加final修饰,唯一不可替换
private final Lock lock = new ReentrantLock();
/**
* 小明 小红
* @param money
*/
public void drawMoney(double money) {
//先获取是谁来取钱
String name = Thread.currentThread().getName();
//同步代码块(小明- 小红) : Ctrl + Alt + t
lock.lock(); //上锁
//操作同一个账户 (this) == acc
//1.判断账户余额是否足够
try {
if (this.money >= money){
//2.取钱
System.out.println(name + "来取钱,取走:" + money);
//3.更新余额
this.money -= money;
System.out.println(name + "来取钱,剩余余额:" + this.money);
}else{
System.out.println(name + "来取钱,余额不足!");
}
} finally { //不管程序报不报错,finally都要执行!
lock.unlock(); //解锁
}
}
五.线程通信
账户类:
package com.wjh.d7_thread_comunication;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//账户类
public class Account {
private String cardId;
private double money;
public Account() {
}
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
/**
* 亲爹 岳父 干爹 存钱(注意线程安全)
* @param money
*/
public synchronized void depositMoney(double money) {
try {
String name = Thread.currentThread().getName();
if(this.money == 0){
//没钱
this.money += money;
System.out.println(name + "来存钱:" + money +"成功! 余额是:" + this.money);
//有钱了,唤醒别人,等待自己!
this.notifyAll(); //唤醒所有线程
this.wait(); //锁对象,让当前进程进入等待!
}else{
//System.out.println(name + "来存钱:没钱");
//有钱,不可存
//唤醒别人.等待自己
this.notifyAll(); //唤醒所有线程
this.wait(); //锁对象,让当前进程进入等待!
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 小明/小红 取钱(注意线程安全)
* @param money
*/
public synchronized void drawMoney(double money) {
try {
String name = Thread.currentThread().getName();
if(this.money >= money){
//钱够
this.money -= money;
System.out.println(name + "来取钱:" + money +"成功! 余额是:" + this.money);
}else{
//System.out.println(name + "来取钱:没钱");
//钱不够,不可取
//唤醒别人.等待自己
this.notifyAll(); //唤醒所有线程
this.wait(); //锁对象,让当前进程进入等待!
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
存钱线程类:
package com.wjh.d7_thread_comunication;
/*
存钱的线程类
*/
public class DepositThead extends Thread{
private Account acc;
public DepositThead(Account acc, String name) {
super(name);
this.acc = acc;
}
@Override
public void run() {
while (true) {
//亲爹 岳父 干爹都来存钱
acc.depositMoney(100000);
try {
Thread.sleep(4000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
取钱线程类:
package com.wjh.d7_thread_comunication;
import com.wjh.d7_thread_comunication.Account;
/*
取钱的线程类
*/
public class DrawThead extends Thread{
private Account acc;
public DrawThead(Account acc, String name) {
super(name);
this.acc = acc;
}
@Override
public void run() {
while (true) {
//小明和小红都来取钱
acc.drawMoney(100000);
try {
Thread.sleep(4000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
测试类:
package com.wjh.d7_thread_comunication;
/*
目标:了解线程通信的流程
*/
public class ThreadDemo {
public static void main(String[] args) {
//使用3个父亲存钱(生产者),2个孩子取钱(消费者) 模拟线程通信思想(一存100000,一取100000)
//1.创建账户对象,代表5个人共同操作的账户
Account acc = new Account("622682",0);
//2.创建两个取钱线程代表小明和小红
new DrawThead(acc, "小明").start();
new DrawThead(acc, "小红").start();
//3.创建三个存钱线程代表:亲爹 岳父 干爹
new DepositThead(acc, "亲爹").start();
new DepositThead(acc, "岳父").start();
new DepositThead(acc, "干爹").start();
}
}
亲爹来存钱:100000.0成功! 余额是:100000.0
小明来取钱:100000.0成功! 余额是:0.0
亲爹来存钱:100000.0成功! 余额是:100000.0
小明来取钱:100000.0成功! 余额是:0.0
亲爹来存钱:100000.0成功! 余额是:100000.0
小明来取钱:100000.0成功! 余额是:0.0
干爹来存钱:100000.0成功! 余额是:100000.0
小红来取钱:100000.0成功! 余额是:0.0
亲爹来存钱:100000.0成功! 余额是:100000.0
小明来取钱:100000.0成功! 余额是:0.0
岳父来存钱:100000.0成功! 余额是:100000.0
小明来取钱:100000.0成功! 余额是:0.0
亲爹来存钱:100000.0成功! 余额是:100000.0
小明来取钱:100000.0成功! 余额是:0.0
干爹来存钱:100000.0成功! 余额是:100000.0
小明来取钱:100000.0成功! 余额是:0.0
岳父来存钱:100000.0成功! 余额是:100000.0
小红来取钱:100000.0成功! 余额是:0.0
干爹来存钱:100000.0成功! 余额是:100000.0
小明来取钱:100000.0成功! 余额是:0.0
亲爹来存钱:100000.0成功! 余额是:100000.0
小红来取钱:100000.0成功! 余额是:0.0
岳父来存钱:100000.0成功! 余额是:100000.0进程已结束,退出代码为 -1
六.线程池(重点:面试必问)
1.线程池概述
2.线程池实现API,参数说明
(重点)
3.线程池处理Runnable任务
package com.wjh.d8_threadpool;
public class MyRunnable implements Runnable {
private int count = 0;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
count++;
System.out.println(count + ":" + Thread.currentThread().getName() + "输出了:HelloWord ==>" + i);
}
try {
System.out.println(Thread.currentThread().getName() + "正在休眠...");
Thread.sleep(50000000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.wjh.d8_threadpool;
/*
目标:自定义一个线程池对象,并测试其特性!
*/
import java.util.concurrent.*;
public class TheadPoolDemo1 {
public static void main(String[] args) {
//1.创建线程池对象
/*
public ThreadPoolExecutor(int corePoolSize, -> 主线程数量
int maximumPoolSize, -> 最大线程数
long keepAliveTime, -> 临时线程最大存活时间
TimeUnit unit, -> 存活时间的单位
BlockingQueue<Runnable> workQueue, -> 指定任务队列
ThreadFactory threadFactory, -> 指定用哪个线程工厂创建线程
RejectedExecutionHandler handler){ -> 处理临时线程(任务拒绝策略)
, 默认:new ThreadPoolExecutor.AbortPolicy() -> (对方正在忙,并向你抛了一个异常)
}
*/
ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS
, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
//2.给任务线程池处理
Runnable target = new MyRunnable();
pool.execute(target); //thread-1
pool.execute(target); //thread-2
pool.execute(target); //thread-3
pool.execute(target); //thread-4
pool.execute(target); //thread-5
pool.execute(target); //thread-6
pool.execute(target); //thread-7
pool.execute(target); //thread-8
//创建临时线程
pool.execute(target); //thread-9
pool.execute(target); //thread-10
//开始抛异常(触发拒绝策略)
//pool.execute(target); //thread-11
//关闭线程池(一般不使用)
//pool.shutdownNow(); //立即关闭,即使任务还没有完成,会丢失任务的!
//pool.shutdown(); //会等待全部任务执行完毕之后再关闭 (建议使用)
}
}
4.线程处理Callable任务
package com.wjh.d8_threadpool;
/*
目标:多线程的创建方式之三:实现Callable接口,结合FutureTask完成.
*/
import java.util.concurrent.Callable;
/*
定义一个任务类,实现Callable接口 必须申明线程任务执行完毕后的结果的数据类型
*/
public class MyCallable implements Callable<String>{ //<String> -> 返回
private int n;
public MyCallable(int n) {
this.n = n;
}
/*
重写call方法(线程的任务方法)
*/
@Override
public String call() throws Exception {
int count = 0;
for (int i = 1; i <= n; i++) {
count += i;
}
return Thread.currentThread().getName() + "执行1-" + n + "子线程执行的结果是:" + count;
}
}
package com.wjh.d8_threadpool;
/*
目标:自定义一个线程池对象,并测试其特性!
*/
import java.util.concurrent.*;
public class TheadPoolDemo2 {
public static void main(String[] args) throws Exception{
//1.创建线程池对象
/*
public ThreadPoolExecutor(int corePoolSize, -> 主线程数量
int maximumPoolSize, -> 最大线程数
long keepAliveTime, -> 临时线程最大存活时间
TimeUnit unit, -> 存活时间的单位
BlockingQueue<Runnable> workQueue, -> 指定任务队列
ThreadFactory threadFactory, -> 指定用哪个线程工厂创建线程
RejectedExecutionHandler handler)
{ -> 处理临时线程(任务拒绝策略) -> 默认:new ThreadPoolExecutor.AbortPolicy() -> (对方正在忙,并向你抛了一个异常)
}
*/
ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS
, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
//2.给任务线程池处理
Future<String> f1 = pool.submit(new MyCallable(100));
Future<String> f2 = pool.submit(new MyCallable(200));
Future<String> f3 = pool.submit(new MyCallable(300));
Future<String> f4 = pool.submit(new MyCallable(400));
Future<String> f5 = pool.submit(new MyCallable(500));
// String rs = f1.get();
// System.out.println(rs);
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
System.out.println(f4.get());
System.out.println(f5.get());
}
}
pool-1-thread-1执行1-100子线程执行的结果是:5050
pool-1-thread-2执行1-200子线程执行的结果是:20100
pool-1-thread-3执行1-300子线程执行的结果是:45150
pool-1-thread-3执行1-400子线程执行的结果是:80200
pool-1-thread-3执行1-500子线程执行的结果是:125250
5.Excutors工具类实现线程池
package com.wjh.d8_threadpool;
/*
目标:使用Executors的工具方法直接得到一个线程池对象
public static ExecutorService newFixedThreadPool (int nThreads)
eg:创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。
*/
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TheadPoolDemo3 {
public static void main(String[] args) throws Exception{
//1.创建固定线程数据的线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(new MyRunnable() );
pool.execute(new MyRunnable() );
pool.execute(new MyRunnable() );
//已经没有多余线程!
pool.execute(new MyRunnable() );
}
}
七.补充知识:定时器
package com.wjh.d9_timer;
/*
目标:timer定时器的使用
*/
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerDemo1 {
public static void main(String[] args) {
//1.创建Timer定时器
Timer timer = new Timer();
//2.调用方法,处理定时任务
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行A1次..." + new Date());
// try {
// Thread.sleep(5000);
// } catch (Exception e) {
// e.printStackTrace();
// }
}
},3000,2000);
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行B1次..." + new Date());
// try {
// System.out.println(10 / 0);
// } catch (Exception e) {
// e.printStackTrace();
// }
}
},3000,2000);
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行C1次..." + new Date());
}
},3000,3000);
}
}
package com.wjh.d9_timer;
/*
目标:timer定时器的使用
*/
import com.wjh.d8_threadpool.MyRunnable;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class TimerDemo2 {
public static void main(String[] args) {
//1.创建ScheduledExecutorService线程池,做定时器
ScheduledExecutorService pool =Executors.newScheduledThreadPool(3);
//2.开启定时任务
pool.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行输出:AA");
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},0, 2, TimeUnit.SECONDS);
pool.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行输出:BB");
//System.out.println(10 / 0);
}
},0, 2, TimeUnit.SECONDS);
pool.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行输出:CC");
}
},0, 2, TimeUnit.SECONDS);
}
}
八.补充知识:并发、并行
九.补充知识:线程的生命周期