多线程
线程概述


线程创建方式
方式一:继承Thread类



package org.example.d1_create;
/**
目标:多线程的创建方式一,继承Thread类实现
*/
public class Demo1 {
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);
}
}
}
方式二:实现Runnable接口


package org.example.d1_create;
/**
目标:学会线程的创建方式二,理解它的优缺点
*/
public class ThreadDemo2 {
public static void main(String[] args) {
//3.创建一个任务对象
Runnable target=new MyRunnable();
//4.把任务对象交给Thread类处理
Thread t=new Thread(target);
//5.启动线程
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("主线程执行输出;"+i);
}
}
}
/**
1.定义线程任务类,实现Runnable接口
*/
class MyRunnable implements Runnable{
//2.重写run方法,定义线程的执行任务
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程执行输出;"+i);
}
}
}

package org.example.d1_create;
/**
目标:学会线程的创建方式二,使用匿名内部类方式
*/
public class Demo2 {
public static void main(String[] args) {
//3.创建一个任务对象
Runnable target=new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程1执行输出;"+i);
}
}
};
//4.把任务对象交给Thread类处理
Thread t=new Thread(target);
//5.启动线程
t.start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程2执行输出;"+i);
}
}
}).start();
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);
}
}
}
方式三:实现Callable接口



package org.example.d1_create;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
目标:学会线程的创建方式三:实现Callable接口,结合FutureTask完成
*/
public class Demo3 {
public static void main(String[] args) {
//3.创建Callable任务对象
Callable<String> call=new MyCallable(100);
//4.把Callable任务对象交给FutureTask对象
//FutureTask对象的作用1:是Runnable的对象(实现了Runnable接口)可以交给Thread了
//FutureTask对象的作用2:可以在线程完毕之后通过调用get方法得到线程执行的结果
FutureTask<String> f1=new FutureTask<>(call);
//5.交给线程处理
Thread t=new Thread(f1);
//6.启动线程
t.start();
Callable<String> call2=new MyCallable(200);
FutureTask<String> f2=new FutureTask<>(call);
//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();
}
}
}
/**
1.定义一个任务类,实现Callable接口 应该申明线程任务执行完毕后的结果的数据类型
*/
class MyCallable implements Callable<String>{
private int n;
public MyCallable(int n) {
this.n = n;
}
/**
2.重写call方法
*/
@Override
public String call() throws Exception {
int sum=0;
for (int i = 0; i <= n; i++) {
sum+=n;
}
return ("子线程执行的结果是:"+sum);
}
}

线程常用方法





package org.example.d2_api;
/**
目标:线程的API
*/
public class Demo1 {
public static void main(String[] args) {
Thread t1=new Thread(()-> {
for (int i = 0; i < 10; i++) {
System.out.println("子线程"+Thread.currentThread().getName()+i); }});
t1.setName("1号");
t1.start();
System.out.println(t1.getName());
Thread t2=new Thread(()-> {
for (int i = 0; i < 10; i++) {
System.out.println("子线程"+Thread.currentThread().getName()+i); }});
t2.setName("2号");
t2.start();
System.out.println(t2.getName());
//哪个线程执行它,它就得到哪个线程对象(当前线程)
Thread m=Thread.currentThread();
m.setName("最牛的线程");
System.out.println(m.getName());
for (int i = 0; i < 5; i++) {
System.out.println(m.getName()+"输出:"+i);
}
}
}

package org.example.d2_api;
public class Demo2 {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
System.out.println("输出"+ i);
if (i==3){
//让线程进入休眠状态
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}


线程安全



package org.example.d3_thread_safe;
/**
目标:模拟取钱案例
*/
public class ThreadDemo {
public static void main(String[] args) {
//1.定义线程类,创建一个共享账户对象
Account acc=new Account("ICBC-111",100000.00);
//2.创建2个线程对象,代表小明和小红同时进来了
new DrawThread(acc,"小明").start();
new DrawThread(acc,"小红").start();
}
}
package org.example.d3_thread_safe;
public class DrawThread extends Thread{
private Account account;
public DrawThread(Account acc,String name){
super(name);
this.account=acc;
}
@Override
public void run() {
account.drawMoney(100000.00);
}
}
package org.example.d3_thread_safe;
public class Account {
private String card;
private double money;
public Account() {
}
public Account(String card, double money) {
this.card = card;
this.money = money;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public void drawMoney(double money) {
//1.判断是谁来取钱
String name=Thread.currentThread().getName();
if (this.money>=money){
//2.取钱
System.out.println(name+"取钱成功,吐出"+money);
//3.更新余额
this.money =this.money-money;
System.out.println(name+"取钱后剩余:"+this.money);
}else {
System.out.println(name+"取钱失败,余额不足");
}
}
}
线程同步


加锁方式一:同步代码块


package org.example.d4_thread_synchronized_code;
public class Account {
private String card;
private double money;
public Account() {
}
public Account(String card, double money) {
this.card = card;
this.money = money;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public void drawMoney(double money) {
//1.判断是谁来取钱
String name=Thread.currentThread().getName();
//加锁
synchronized (this) {
if (this.money >= money){
//2.取钱
System.out.println(name+"取钱成功,吐出"+money);
//3.更新余额
this.money =this.money-money;
System.out.println(name+"取钱后剩余:"+this.money);
}else {
System.out.println(name+"取钱失败,余额不足");
}
}
}
}
package org.example.d4_thread_synchronized_code;
public class DrawThread extends Thread{
private Account account;
public DrawThread(Account acc, String name){
super(name);
this.account=acc;
}
@Override
public void run() {
account.drawMoney(100000.00);
}
}
package org.example.d4_thread_synchronized_code;
/**
目标:模拟取钱案例
*/
public class ThreadDemo {
public static void main(String[] args) {
//1.定义线程类,创建一个共享账户对象
Account acc=new Account("ICBC-111",100000.00);
//2.创建2个线程对象,代表小明和小红同时进来了
new DrawThread(acc,"小明").start();
new DrawThread(acc,"小红").start();
}
}
加锁方式二:同步方法



package org.example.d5_thread_synchronized_method;
public class Account {
private String card;
private double money;
public Account() {
}
public Account(String card, double money) {
this.card = card;
this.money = money;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public synchronized void drawMoney(double money) {
//1.判断是谁来取钱
String name=Thread.currentThread().getName();
if (this.money>=money){
//2.取钱
System.out.println(name+"取钱成功,吐出"+money);
//3.更新余额
this.money =this.money-money;
System.out.println(name+"取钱后剩余:"+this.money);
}else {
System.out.println(name+"取钱失败,余额不足");
}
}
}
加锁方式三:lock锁

package org.example.d6_thread_lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Account {
private String card;
private double money;
//final修饰:锁对象唯一
private final Lock lock=new ReentrantLock();
public Account() {
}
public Account(String card, double money) {
this.card = card;
this.money = money;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public void drawMoney(double money) {
//1.判断是谁来取钱
String name=Thread.currentThread().getName();
lock.lock();
try {
if (this.money>=money){
//2.取钱
System.out.println(name+"取钱成功,吐出"+money);
//3.更新余额
this.money =this.money-money;
System.out.println(name+"取钱后剩余:"+this.money);
}else {
System.out.println(name+"取钱失败,余额不足");
}
} finally {
lock.unlock();
}
}
}
线程通信



package org.example.d7_thread_conmminute;
public class Account {
private String card;
private double money;
public Account() {
}
public Account(String card, double money) {
this.card = card;
this.money = money;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
/**
亲爹,干爹,岳父存钱
* @param money
*/
public synchronized void deposit(double money){
try {
String name=Thread.currentThread().getName();
if (this.money==0){
this.money +=money;
System.out.println(name+ "存钱"+money+"成功,余额为:"+this.money);
//有钱了,唤醒别人,等待自己
this.notify();
this.wait();
}else {
//有钱不存
this.notify();
this.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 取钱
* @param money
*/
public synchronized void drawMoney(double money) {
try {
//1.判断是谁来取钱
String name=Thread.currentThread().getName();
if (this.money>=money){
//2.取钱
System.out.println(name+"取钱成功,吐出"+money);
//3.更新余额
this.money =this.money-money;
System.out.println(name+"取钱后剩余:"+this.money);
//没钱了
this.notify();
this.wait();
}else {
System.out.println(name+"取钱失败,余额不足");
//钱不够,不能取
//唤醒别人,等待自己
this.notify();
this.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package org.example.d7_thread_conmminute;
public class DrawThread extends Thread{
private Account account;
public DrawThread(Account acc, String name){
super(name);
this.account=acc;
}
@Override
public void run() {
while (true) {
account.drawMoney(100000.00);
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package org.example.d7_thread_conmminute;
public class DepositThread extends Thread{
private Account acc;
public DepositThread(Account acc,String name){
super(name);
this.acc=acc;
}
@Override
public void run() {
while (true) {
acc.deposit(100000.00);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package org.example.d7_thread_conmminute;
/**
目标:了解线程通信的流程
*/
public class ThreadDemo {
public static void main(String[] args) {
//使用三个爸爸存钱(生产者),俩个孩子取钱(消费者),模拟线程通信思想
//创建账户对象,代表五个人共同操作的对象
Account acc=new Account("ICCBC",0);
//创建2个线程对象代表小明和小红
new DrawThread(acc,"小明").start();
new DrawThread(acc,"小红").start();
//创建3个线程对象代表三个爸爸
new DepositThread(acc,"亲爹").start();
new DepositThread(acc,"干爹").start();
new DepositThread(acc,"岳父").start();
}
}
线程池
线程池概述和创建线程





线程池处理Runnable、Callable任务


package org.example.d8_threadpool;
import java.lang.reflect.Executable;
import java.util.concurrent.*;
/**
目标:自定义一个线程池对象,并测试其特性
*/
public class ThreadPoolDemo1 {
public static void main(String[] args) {
//1.创建线程池对象
/*
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)*/
ExecutorService pool=new ThreadPoolExecutor(3,5,8,
TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
//2.给任务线程池处理
Runnable target=new MyRunnable();
//核心线程处理
pool.execute(target);
pool.execute(target);
pool.execute(target);
//放进任务队列
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
//若核心线程在忙,任务对列已满,则创建临时线程
pool.execute(target);
pool.execute(target);
//若最大线程数在忙,任务队列已满,则抛出异常
//pool.execute(target);
//关闭线程池,开发中一般不会使用
//pool.shutdownNow();//立即关闭,即使任务没有完成,会丢失数据
pool.shutdown();//会等待任务执行完毕后在进行关闭
}
}

package org.example.d8_threadpool;
import java.util.concurrent.Callable;
/**
1.定义一个任务类,实现Callable接口 应该申明线程任务执行完毕后的结果的数据类型
*/
class MyCallable implements Callable<String>{
private int n;
public MyCallable(int n) {
this.n = n;
}
/**
2.重写call方法
*/
@Override
public String call() throws Exception {
int sum=0;
for (int i = 0; i <= n; i++) {
sum+=n;
}
return (Thread.currentThread().getName()+"线程执行1--->"+n+"的和是:"+sum);
}
}
package org.example.d8_threadpool;
import java.util.concurrent.*;
/**
目标:自定义一个线程池对象,并测试其特性
*/
public class ThreadPoolDemo2 {
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)*/
ExecutorService pool=new ThreadPoolExecutor(3,5,8,
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));
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());
}
}
Executors的工具类构建线程池对象



package org.example.d8_threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
目标:使用Executors的工具方法直接接得到一个线程池对象
*/
public class ThreadPoolDemo3 {
public static void main(String[] args) {
//1、创建固定线程数据的线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(new MyRunnable());
pool.execute(new MyRunnable());
pool.execute(new MyRunnable());
pool.execute(new MyRunnable());
}
}
补充知识
定时器


Timer定时器的特点和存在的问题
- Timer是单线程,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入。
- 可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续任务执行。

package org.example.d9_timer;
import com.sun.jmx.snmp.tasks.Task;
import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
目标:Timer定时器的使用和了解
*/
public class TimerDemo2 {
public static void main(String[] args) {
//创建一个ScheduledExecutorService对象,做定时器
ScheduledExecutorService pool= Executors.newScheduledThreadPool(3);
//开启定时任务
pool.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了AAA\t"+ new Date());
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
}
},0,2, TimeUnit.SECONDS);
pool.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了BBB\t"+new Date());
System.out.println(10/0);
}
},0,2, TimeUnit.SECONDS);
pool.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了CCC\t"+new Date());
}
},0,2, TimeUnit.SECONDS);
}
}
并发并行


线程的生命周期



本文详细介绍了Java中多线程的创建,包括继承Thread类、实现Runnable接口以及使用Callable接口。还探讨了线程的常用方法,如线程安全问题和解决策略,包括同步代码块、同步方法和Lock锁。此外,文章还讨论了线程通信示例以及线程池的使用,如ThreadPoolExecutor和Executors工具类。最后提到了定时器Timer在并发编程中的应用。
593

被折叠的 条评论
为什么被折叠?



