JAVA---创建线程的4种方式
1.创建线程的4种方式
方式一:
继承Thread,缺点,java是单继承,如果继承了Thread就不能继承其他类
方式二:
实现runnable()接口,通常不直接在类上实现runnable接口,与类的耦合度高
方式三:实现callable()接口 和futrue使用
与实现runnable接口相比,callable()有返回值,且自带异常处理
方式四:使用线程池
2.各种锁的java实现方式
通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!
-------------------------------
ThreadDemo类
package com.javasm;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
public class UserInfo {
final Object object = new Object();
private Integer age;
private String name;
private Integer balance;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getBalance() {
return balance;
}
public void setBalance(Integer balance) {
this.balance = balance;
}
public UserInfo(Integer age, String name, Integer balance) {
this.age = age;
this.name = name;
this.balance = balance;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
protected boolean flag = true;
int count = 0;
public void getMoney() {
while (flag) {
synchronized (this) {
if (balance <= 0) {
System.out.println("余额不足");
flag = false;
return;
}
count++;
balance -= 1000;
System.out.println(Thread.currentThread().getName() + "取走了"+name+"1000元" + "剩余:" + balance + "-" + "第" + count + "次取钱");
}
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public void setMoney() {
balance += 1000;
System.out.println(Thread.currentThread().getName() + "往账户存入1000" + "剩余:" + balance+"元");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
--------------------------
UserInfo类
package com.javasm;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
public class UserInfo {
final Object object = new Object();
private Integer age;
private String name;
private Integer balance;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getBalance() {
return balance;
}
public void setBalance(Integer balance) {
this.balance = balance;
}
public UserInfo(Integer age, String name, Integer balance) {
this.age = age;
this.name = name;
this.balance = balance;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
protected boolean flag = true;
int count = 0;
public void getMoney() {
while (flag) {
synchronized (this) {
if (balance <= 0) {
System.out.println("余额不足");
flag = false;
return;
}
count++;
balance -= 1000;
System.out.println(Thread.currentThread().getName() + "取走了"+name+"1000元" + "剩余:" + balance + "-" + "第" + count + "次取钱");
}
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public void setMoney() {
balance += 1000;
System.out.println(Thread.currentThread().getName() + "往账户存入1000" + "剩余:" + balance+"元");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
2.-------------------
1. 实现多线程的4种方式
2. 解决线程安全方案
1.1 并行 vs 并发
同一时间做多个任务。
1. 并行
约女朋友:
你: 看一场电影 买一束花 烛光晚餐 处理器
2h 30min 2h 4.5H
看电影期间: 给花店老板发信息 订花
给饭店订桌:
系统级别的并发/并行 多个处理器
并行 vs 串行:----> 计算能力
串行: 线性完成 4.5H
Stream.stream()
paralellStream()
1000个数据:
找最大值: 串行: 冒泡
并行:
放到多个任务中 10任务---> 100个数据
并发:
用户级别的并发。 三高: 高并发 高性能 高可用
买火车票 秒杀---> 加服务器 ---> 服务器集群 负载均衡
tomcat: 200个并发
mysql: 151并发
1.2 同步 vs 异步
请求。
同步:
一个新任务的开始必须等待另外一个任务结束。 线程阻塞(状态)
异步:
一个新任务的开始不需要等待另外一个任务结束。
ajax(异步刷新页面) 定时任务
1.3 阻塞 vs 非阻塞
类似于堵车。
状态
Scanner input = new Scanner(System.in); IO---> BIO blocking io 阻塞的IO
BIO: 同步阻塞IO
NIO: 同步非阻塞IO
AIO: 异步非阻塞IO ---> 即时通讯软件 netty tomcat ---> NIO 第二阶段
1.4 进程 vs 线程
进程:
一个应用软件就是一个进程。 占据CPU和内存
运行内存: ANDROID 8g 12g 16g
IOS: 2g 3G 4G 单任务
线程:
比进程小的执行单元。一个进程里面有n个线程。线程与线程之间是相互独立。---> 独有的线程栈
与多线程进行关联
同步非阻塞: 多个线程同时执行(一个一个进行执行) 不会出现阻塞
同步阻塞: 多个线程都不做任务了
异步阻塞:
多个线程并发执行 都阻塞了
异步非阻塞:
多个线程并发执行 都正常执行
==2. Thread==
jvm支持多线程。
代表程序里面的线程。每个线程都有优先级别 理论上级别越大, 先被执行的概率就越大(事实上还要看cpu的调度器以及上下文切换时间)。
public class Thread extends Object implements Runnable
内部类:
static class Thread.State 线程生命周期
属性
1-10
static int MAX_PRIORITY 10
static int MIN_PRIORITY 1
static int NORM_PRIORITY 5
常用构造
Thread(Runnable target)
Thread(Runnable target, String name) 每个线程都有名字
Thread(String name)
常用功能
static Thread currentThread() 获得当前正在运行线程
long getId() 获得线程的id 1
String getName()
int getPriority()
void setName(String name) 修改线程名称
void setPriority(int newPriority)
Thread.State getState() 获得线程状态
void join() 等待这个线程死亡。 ----> 等待线程结束
void join(long millis) 在指定时间内 优先让当前执行 10
void run() 当前线程运行逻辑都在run里面 (禁止调用)
static void sleep(long millis) 不会释放锁对象
在指定时间内休眠 超时了继续执行下面的功能 线程调度 抢占cpu的机会让给了其它线程
void start() 启动线程 自动调用run方法
static void yield() 线程礼让 当前线程礼让其他线程 自己立马处于就绪状态
线程通信 : 必须在同步使用
Object:
void wait() 当前线程等待 (一直等)
void wait(long timeout) 当前线程再指定时间内处于等待 超时了 自己醒过来 自动释放锁对象
void notify() 在一个线程里面唤醒其它随机一个wait的线程
void notifyAll() 在一个线程里面唤醒所有的wait的线程
//jvm底层默认至少有2个线程: main GC守护线程
public static void main(String[] args) {
System.out.println("main线程开始。。。。。。。。。。。。。。。。");
//获得当前正在运行的线程
Thread currentThread = Thread.currentThread();
System.out.println(currentThread);//Thread[main,5,main]
System.out.println(currentThread.getName());
System.out.println(currentThread.getPriority());
System.out.println(currentThread.getId());//1
//线程调度
// try {
// //Thread.sleep(2000);
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
currentThread.setName("main线程");
currentThread.setPriority(Thread.MAX_PRIORITY);
System.out.println(currentThread);
System.out.println(currentThread.getState());//运行状态
System.out.println("main线程结束。。。。。。。。。。。。。。。。");
}
3. 创建多线程
并发
3.1 继承Thread
public class 类 extends Thread{
}
模拟多线程下载小说资源:
public class DownloadNovelUtil {
private DownloadNovelUtil() {
}
private static final String TARGET_DIR = "day20/novel/";//父级目录
/**
* 小说资源
*
* @param novelPath 小说资源路径
* @param fileName 目标文件名称
*/
public static void download(String novelPath, String fileName) {
//读写
try (
BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(novelPath).openStream()));
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(TARGET_DIR, fileName)))
) {
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("<div class=\"read-content j_readContent\" id=\"\">")) {
String novel = reader.readLine();
writer.write(novel.replaceAll("<p>", "\n"));
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//开启多个线程
//5个小说章节
String[] pathArray = {
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/r-8gWkBp14PwrjbX3WA1AA2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/6hDiaxEV_bXgn4SMoDUcDQ2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2",
"https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2"
};
List<Thread> threadList = new ArrayList<>(10);
for (int i = 0; i < pathArray.length; i++) {
DownloadNovelThread thread = new DownloadNovelThread(i + "", pathArray[i], i + ".txt");
threadList.add(thread);
}
threadList.forEach(Thread::start);
}
public class DownloadNovelThread extends Thread {
private String novelPath;
private String fileName;
//重写父类run方法
==3.2 实现Runnable==
需求:
模拟多个窗口(线程)同时卖票。100张票
public class SaleTicket {
private int ticketNum = 100;//一共卖100张票
//方法: 卖票
public void sale() {
while (ticketNum > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticketNum--) + "票");
try {
TimeUnit.MILLISECONDS.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
//开5个窗口
//创建5个线程对象 Thread
SaleTicket saleTicket = new SaleTicket();
new Thread(saleTicket::sale, "窗口1").start();
new Thread(saleTicket::sale, "窗口2").start();
new Thread(saleTicket::sale, "窗口3").start();
new Thread(saleTicket::sale, "窗口4").start();
new Thread(saleTicket::sale, "窗口5").start();
//实现了并发 创建多个线程的----> 数据不对 数据紊乱情况 ---> 并发编程里面的 线程安全的问题
// List<Thread> list = new ArrayList<>(10);
// for (int i = 1; i <= 5; i++) {
// list.add(new Thread(saleTicket::sale, "窗口" + i));
// }
//
// list.forEach(Thread::start);
}
3.3 实现Callable<T>+Future
模拟取钱或者存钱功能:
FutureTask(Callable<V> callable)
public class AccountBalance {
public class MoneyTest {
public static void main(String[] args) {
//张三 借给了 王五 500
//张三 借给了 李四 1000
//王五/李四同时进行转账 Thread
//Thread(Runnable target, String name)
//需要Callable必须与Runnable扯上关系
AccountBalance accountBalance = new AccountBalance();
//王五的任务
FutureTask<Integer> task1 = new FutureTask<>(() -> {
accountBalance.quMoney(500);
return accountBalance.getBalance();
});
//李四的任务
FutureTask<Integer> task2 = new FutureTask<>(() -> {
accountBalance.cunMoney(1000);
return accountBalance.getBalance();
});
//开启多线程
Thread wangwu = new Thread(task1, "王五");
Thread lisi = new Thread(task2, "李四");
wangwu.start();
lisi.start();
try {
task1.get();//获得回调结果 阻塞线程
task2.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// try {
// wangwu.join();
// lisi.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//张三本人来了
//查看账户余额剩下多少----> 等待前面线程执行完毕之后
System.out.println("张三账户余额:" + accountBalance.getBalance());
}
}
==3.4 线程池==
public class ThreadPoolTest {
static int num=1;
public static void main(String[] args) {
//JUC 并发编程
//ThreadPoolExecutor
//1.Executors 执行器 快捷方式来创建线程池
//Executor executor = Executors.newFixedThreadPool(100);//创建固定10个线程对象
//Executor executor = Executors.newCachedThreadPool();//可伸缩的线程池
//Executor executor = Executors.newSingleThreadExecutor();//池子里面最多存储1个线程对象
//Executor executor = Executors.newScheduledThreadPool(10);
// public ThreadPoolExecutor(int corePoolSize, 初始化线程对象的数量 5
// int maximumPoolSize, 可允许的最大的线程数量 100
// long keepAliveTime, 空闲线程对象的回收时间 10
// TimeUnit unit, keepAliveTime的时间单位
// BlockingQueue<Runnable> workQueue, 任务队列---> 未执行的任务存储队列里面
//1. ArrayBlockingQueue 有界队列 100
//2. LinkedBlockingDeque 无界队列
//3. PriorityBlockingQueue 优先队列
//4. SynchronousQueue 同步队列
// ThreadFactory threadFactory, 创建线程对象
// RejectedExecutionHandler handler) {
//1. 任务的数量> maximumPoolSize+队列 采取的拒绝策略 main ThreadPoolExecutor.CallerRunsPolicy
ThreadPoolExecutor poolExecutor =
new ThreadPoolExecutor(10,
100,
10,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(30),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
//直接提交任务---> submit/execute
// for (int i = 0; i < 1000; i++) {
// poolExecutor.submit(() -> {
// DownloadNovelUtil
// .download("https://read.qidian.com/chapter/mqKKVE5puX825kCkTf2hCw2/z6saMvwEsFmaGfXRMrUjdw2", "b"+(num++)+".txt");
// });
// }
SaleTicket saleTicket = new SaleTicket();
poolExecutor.submit(saleTicket::sale);
poolExecutor.submit(saleTicket::sale);
poolExecutor.submit(saleTicket::sale);
poolExecutor.submit(saleTicket::sale);
poolExecutor.submit(saleTicket::sale);
poolExecutor.submit(saleTicket::sale);
poolExecutor.submit(saleTicket::sale);
//任务量>初始化量+队列 创建新的线程对象
}
4. 线程安全
线程安全是==编程==中的术语,指某个==程序==在==并发==环境中被调用时,能够正确地处理==多线程==之间的==公共变量==,使程序功能正确完成。
并发 多线程 共享的全局变量
线程与线程之间相互独立的 互不沟通的 A线程对变量值的修改 其它线程而言 不知道 ==有各自的工作内存==。
内存: 存储数据
jvm并发里面问题 与 计算机里面机制是完全一样的。
内存模型: MM memory model
CPU 计算能力---> 磁盘(读写数据 IO) 成正比
cpu 计算能力 变得很快 ----> 不成正比
缓存: 数据的copy 体积小 效率快 比较昂贵
读写数据 先操作缓存的数据 缓存没有 操作磁盘
L1---> L2---L3
每一核: 都有L1 L2
单核cpu 单线程: 没有问题
单核cpu 多线程: 没有
多核cpu 多线程: 有
计算机: 缓存一致性的协议。MESI
处理器优化: 指令重排 提高cpu的利用率
java内存结构: 运行数据区
根本原因: 1. 内存屏障 2. 处理器优化
JMM: java内存模型
描述并发编程里面出现的一系列问题 并提供解决的方案。
1. 内存可见性: 一个线程数据的改变 对另外一个线程 不可见的 每个线程都有独立的工作内存
2. 有序性: 一行一行去执行的
创建对象: 3步
1. 开辟内存空间 3ms
2. 初始化成员变量数据 3ms
3. 赋值 1ms
1 3 4ms
3. 原子性: 一个程序要么全部成功 要么全部失败
i++;// i--; 不能保证原子性
取值 运算 赋值
1.提供很多指令集解决并发里面的问题, monitor enter / monitor exit final
synchronized Lock volatile
synchronized(同步)/Lock: 保证并发内存可见性 有序性 原子性
一个时间内值允许一个线程执行功能(类似于单线程)----> 效率低---> 1.8+ 效率很快
volatile:
(一写多读)保证并发内存可见性 有序性 但是不能保证原子性 限制指令重排
volatile 效率高于 synchronized
4.1 synchronized
StringBuffer / Vector
1. 同步方法
public class SaleTicket {
private int ticketNum = 30;
public void sale() {//上锁
while (ticketNum > 0) {
ticket();
try {
TimeUnit.MILLISECONDS.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}//释放锁
//锁对象----> 任意一个对象都可以充当锁对象
//必须是同一个锁对象
//当前类的this
private synchronized void ticket() {
if (ticketNum > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticketNum--) + "票");
}
}
}
public class SaleTicket {
private static int ticketNum = 30;
public static void sale() {
while (ticketNum > 0) {
ticket();
try {
TimeUnit.MILLISECONDS.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//锁对象----> 任意一个对象都可以充当锁对象
//必须是同一个锁对象
//普通的功能方法: 当前类的this
//静态方法: SaleTicket.class---> Class<SaleTicket> clazz 类锁
private static synchronized void ticket() {//自动上锁
if (ticketNum > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticketNum--) + "票");
}
}//自动释放锁
}
2. 同步代码块
synchronized("锁对象"){
//有可能会出现线程安全的逻辑
}
public class AccountBalance {
4.2 Lock
try{
}finally{
}
public class AccountBalance {
4.3 Volatile
为什么不能保证原子性?
该如何保证原子性?
案例: 模拟id生成器
public class IdGenerator {
private static int id = 0;//维护id
public synchronized static void idIncrement() {
id++;
//取值
//运算
//赋值
// A++ B++
}
public static int getId() {
return id;
}
}
使用synchronized能够保证原子性。 效率偏慢。
public class IdGenerator {
//并发编程里面: 能够保证原子性类
//Atomic
//private static int id = 0;
// private static AtomicLong id = new AtomicLong();
//LongAdder
private static LongAdder id = new LongAdder();
static {
id.add(1000);
}
public static void idIncrement() {
// id.incrementAndGet();// CAS 乐观锁
id.increment();
}
public static long getId() {
//return id.get();
return id.longValue();
}
}
public class IdGenerator {
//并发编程里面: 能够保证原子性类
//Atomic
//private static int id = 0;
// private static AtomicLong id = new AtomicLong(1000);
//LongAdder
private static LongAdder id = new LongAdder();
static {
//设置初始值
id.add(1000);
}
public static void idIncrement() {
// id.incrementAndGet();// CAS 乐观锁
id.increment();
}
public static long getId() {
//return id.get();
return id.longValue();
}
}
5. 死锁
并发 互相争夺的资源(2个) ----> 良好的释放锁对象
张三 李四 约好画画。
张三:画笔
李四:颜料
public static void main(String[] args) {
//创建2个线程
// 张三:画笔
// 李四:颜料
final String pen = "画笔";
final String color = "颜料";
new Thread(() -> {
String name = Thread.currentThread().getName();
synchronized (pen) {//上锁
System.out.println(name + "有" + pen);
}
synchronized (color) {
System.out.println(name + "想要李四的" + color);
}
}, "张三").start();
new Thread(() -> {
String name = Thread.currentThread().getName();
synchronized (color) {//上锁
System.out.println(name + "有" + color);
}//释放锁
synchronized (pen) {
System.out.println(name + "想要张三的" + pen);
}
}, "李四").start();
}
6. 线程通信
生产者和消费者这个现象。
生产者: 生产数据 放到池子中(大小) 池子满 等一等
缓冲区(池子)
消费者: 结合排队的概念 优先处理先提交过来的数据 也不能一直消费 等一等
Object: 不能随便调用 必须结合synchronized 锁对象调用wait/notify
wait()
notify()/notify()
用户提交订单---> 订单池
支付宝的服务器--->从订单池里面 获得用户先提交的订单进行处理
public class OrderPool {
//创建容器
private LinkedList<String> pool = new LinkedList<>();//30个订单
public synchronized void produceOrder() {
try {
while (pool.size() == 20) {
this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.add("order");
//唤醒消费者处理
this.notifyAll();
System.out.println(Thread.currentThread().getName() + "提交1个order,目前池子里面:" + pool.size());
}
public synchronized void consumeOrder() {//监视器对象 this
//保证池子里面 有订单
try {
while (pool.size() == 0) {//使用if 有可能会出现虚假唤醒
//对于服务器而言 需要等待
this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.remove(0);
//唤醒用户提交订单
this.notifyAll();
System.out.println(Thread.currentThread().getName() + "处理1个order,目前池子里面:" + pool.size());
}
}
public static void main(String[] args) {
OrderPool pool = new OrderPool();
//创建3个用户线程
List<Thread> userThread = new ArrayList<>();
for (int i = 1; i <= 3; i++) {
userThread.add(new Thread(() -> {
while (true) {
pool.produceOrder();
try {
TimeUnit.MILLISECONDS.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "用户" + i));
}
//创建2个服务器线程
List<Thread> serverThread = new ArrayList<>();
for (int i = 1; i <= 2; i++) {
serverThread.add(new Thread(() -> {
while (true) {
pool.consumeOrder();
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "服务器" + i));
}
userThread.forEach(Thread::start);
serverThread.forEach(Thread::start);
}
}
面试题: sleep(time) VS wait()
1. 所属不同
Thread.sleep() Object.wait()
2. 唤醒方式不同
sleep(time) 超时自动醒过来 调度
Object.wait(time)超时自动醒过来/或者notify
Object.wait() 只能使用notify
3. 调用方式不同
sleep(time) 在任意类的方法里面都可以被调用
必须在同步方法/代码块: 监视器对象.wait()
4. 是否释放锁对象
sleep() 没有的
wait() 自动释放锁对象
lock+Condition
public class OrderPool {
//创建容器
private LinkedList<String> pool = new LinkedList<>();//30个订单
//Lock+Condition
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();//包装了Object里面的wait/notify
public void produceOrder() {
lock.lock();
try {
try {
while (pool.size() == 20) {
condition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.add("order");
//唤醒消费者处理
condition.signalAll();
System.out.println(Thread.currentThread().getName() + "提交1个order,目前池子里面:" + pool.size());
} finally {
lock.unlock();
}
}
public void consumeOrder() {//监视器对象 this
//保证池子里面 有订单
lock.lock();
try {
try {
while (pool.size() == 0) {//使用if 有可能会出现虚假唤醒
//对于服务器而言 需要等待
condition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.remove(0);
//唤醒用户提交订单
condition.signalAll();
System.out.println(Thread.currentThread().getName() + "处理1个order,目前池子里面:" + pool.size());
} finally {
lock.unlock();
}
}
}
7. 线程状态
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,// new 线程对象 新建状态
RUNNABLE,// run方法 运行状态
/**
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,//阻塞状态----> 释放锁对象---> notify
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
*/
WAITING,//等待 notify
/**
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* </ul>
*/
TIMED_WAITING,//时间内等待
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;//死亡状态
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix