Java线程
# Java线程
# 线程与进程
线程 是进程中的执行过程,一个进程包含有多个线程,并发执行
进程 是一个运行的应用程序,每个进程都有自己独立的内存空间
一个程序运行后至少有一个进程,一个进程里可包含多个线程!
进程特点:
- 独立性: 进程是系统中独立存在的实体,他可以拥有自己的独立资源,每个进程都有自己的独立空间,未经进程本身的允许,用户线程不可以直接访问其他线程的地址空间
- 动态性: 进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合,即线程加入了时间的概念。进程具有自己的声明周期和不同的状态,这些概念而程序都不具备有
- 并发性: 多个进程可以在单个处理器上进行并发执行,而且多个线程之间是互不干扰的
并发相关概念
- 并发: 同一时刻只能执行一条指令
- 并行: 同一时刻执行多条不同指令
- 同步: 执行完上条线程才能执行下条线程(类似接力)
- 异步: 线程之间互不等待,线程启动即执行
# 线程实现
实现线程线程主要有
- java.lang.Thread类
- Runnable接口
- Callable接口
# Thread类
Thread类中实例化的对象代表线程,启动需要Thread实例
构造方法
构造方法 | 说明 |
---|---|
Thread() | - |
Thread(String name) | 指定线程名称 |
Thread(Runnable target) | |
Thread(Runnable target , String name) |
常用方法
修饰符 | 方法 | 说明 |
---|---|---|
Thread | currentThread() | 返回对当前正在执行的线程对象的引用 |
long | getId() | 返回线程标识符 |
String | getName() | 返回线程名称 |
int | getPriority() | 返回线程的优先级 |
Thread.State | getState() | 返回线程的状态 |
void | interrupt() | 中断线程 |
boolean | isAlive() | 线程是否运行 |
boolean | isInterrupted() | 线程是否被中断 |
void | run() | 调用该Runnable对象的run方法 |
void | start() | 线程开始执行run方法 |
void | sleep(long ms) | 线程以指定的毫秒数暂停(等待) |
void | join() | 在线程中加入另一个线程 |
boolean | interrupted() | 中断线程 |
void | setPriority(int newPriority) | 设置线程的优先级newPriority的范围(1-10) |
void | setDaemon(boolean on) | 是否设置守护线程。守护线程:主线程结束,子线程也跟着结束 |
String | toString() | 返回线程的字符串表示、线程的名、优先级、线程组 |
start()与run()的区别
start()启动一个新线程 , 并执行run()方法中的逻辑
# Runnable接口
线程一般通过Thread类创建的。但 Runnable接口 也可以实现进程
优点
- 适合多线程同时执行相同的任务
- 可多个相同程序处理统一资源 (资源共享
- 不受 类的单继承约束
实现方式
- ==Thread(Runnable target)==
- ==Thread(Runnable target , String name)==
# Callable接口
Runnable接口 比 Callable接口 少了 线程结束无返回值 和 不能抛出异常 ,而 Callable接口 正是弥补这一缺陷!
特点:
- 不能共享资源
- 线程执行完毕有返回值
- 线程可抛出异常
应用步骤:
- 设计一个类, 实现Callable接口
- 重写 Call() 方法(类似于 Thread中的run)
- 创建实例 FutureTask对象 进行封装 实现Callable的类
- 创建实例 Thread对象 再次封装 FutureTask对象
- Thread对象 start() 启用线程
- 线程执行结束后 ,FutureTask对象可通过 get() 获取 Call() 方法的返回值
PS: FutureTask类 和 Callable接口 都需要泛型 否则应用可能报错 (泛型也意味着返回类型)
//1. 编写 Callable接口 , 实现 call抽象方法
class MyCallable implements Callable<T>{
@Ovrride
public <T> call() throws Exception{
return T;
}
}
//2. 创建FutureTask对象,并传入第一步编写的Callable类对象
FutureTask<T> future = new FutureTask<>(callable);
//3. 通过Thread,启动线程
new Thread(future).start();
//4. 获取返回值,FutureTask对象中的get()方法获取返回值(此方法有堵塞效果)
future.get();
FutureTask类 说明:用于异步获取执行结果或取消执行任务的作用(线程池的核心)
# 线程应用总结
Thread | Runnable | Callable | |
---|---|---|---|
类型 | 类 | 接口 | 接口 |
实现 | 单继承实现 | 可多实现继承 | 可多实现继承 |
返回 | 无 | 无 | 有 |
回调 | 方法直接调用 | 调用Thread的静态方法 | 调用Thread的静态方法 |
复杂度 | 简单 | 简单 | 复杂 |
推荐用 | N | Y | Y |
# 线程控制
# 线程休眠
sleep(long ms)
方法 停止多少秒。它可能会抛出InterruptedException异常,所以放在try-catch块中。暂停后醒来,不能保证它能立即运行!
//休眠1s
Thread.sleep(1000);
# 线程加入
在多个线程并行的过程中,某个线程被join()方法执行,其他需要等待join线程完成才能结束
修饰符 | 方法 | 说明 |
---|---|---|
void | ==join()== | 等待这个线程死亡 |
void | ==join(long millis)== | 等待这个线程死亡,最长时间为millis ms |
void | ==join(long millis , int nanos)== | 等待最多millis ms 加上这个线程死亡的nanos 纳秒 |
**注意:**线程在被启动后 join()方法 才有效!
/** Join线程
* 但在某个过程其他线程在执行流中调用其他线程的join()方法时,调用线程被堵塞,直到join线程执行完为止
* 等待这个线程死掉,才执行(此方法的调用与调用的行为方式完全相同)
*/
public class JoinThread extends Thread {
public JoinThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0 ; i < 100 ; i++) {
if (i == 99) System.out.println(getName() + " : " + i);
}
}
/** 测试原理
* 创建多个线程,让任意一线程 join加入
* 1. main线程 和 newThread线程 并行启动,分别循环100次
* 2. main线程循环到 10 jion线程 加入,并 jion() 执行
* 结论:
* 线程完毕顺序:newThread -> join -> main
*/
public static void main(String[] args) throws InterruptedException {
new JoinThread("newThread").start();
for (int i = 0 ; i < 100 ; i++) {
if (i == 10) {
JoinThread jt = new JoinThread("Join线程");
jt.start();
/**
* 优先执行
*/
jt.join();
}
if (i == 99) System.out.println(Thread.currentThread().getName() + " : " + i);
}
}
}
/** 控制台结果
* newThread : 99
* Join线程 : 99
* main : 99
*/
newThread线程 并非与 main线程 并行启动。join线程 是在 main线程 内设置的因此 main线程 需要等待 join线程 跑完
# 线程后台
后台线程是在所有前台的线程都死亡后,后台线程会自动死亡,后台线程的主要任务是为其他线程提供服务的(如:JVM垃圾回收线程(后台线程)
==Thread.setDaemon(true)== 即可将线程设置为后台线程
注意:==Thread.setDaemon(true)==方法 必须在线程启动前设置为后台线程。因 后台线程的自动死亡是通过 前台线程死亡所收到的通知,并加以判断是否只剩后台线程,从而执行死亡的指令,在这一过程需要一定时间
/** 后台线程
* 说明1:将此线程标记为守护线程或用户线程。当唯一运行的线程都是守护线程时,Java 虚拟机退出。此方法必须在线程启动之前调用。
* 说明2:当所有前台的线程都死亡后,后台线程会自动死亡
*/
public class DemonThread extends Thread{
@Override
public void run() {
for (int i = 0 ; i < 1000 ; i++) {
System.out.println(getName()+" : "+i);
}
}
/** 测试原理
* 满足条件其他线程都要比后台线程更早结束
* 主线程main:执行循环 10 次
* 后台线程dt:执行循环 1000 次
*
*/
public static void main(String[] args) {
DemonThread dt = new DemonThread();
/**
* 设置为 后台线程
*/
dt.setDaemon(true);
dt.start();
for (int i = 0 ; i < 10 ; i++) {
System.out.println(Thread.currentThread().getName()+" : "+i);
}
}
}
不难看出 dt线程 后台线程 不能执行到 i = 999 的情况
# 线程唤醒
线程唤醒的操作,需要搭配 synchronized + wait + notify 共同完成的
注意:
- 方法一般作用于 同步锁,在调用这些方法前提需要搭配 synchronized同步锁使用,以防多线程错乱
- 如果 当前线程在同步锁 的作用下,且被 同步锁 调用了 wait()方法,同步锁将会释放,用于给别的线程获取执行唤醒操作
- 唤醒线程使用的类是 ==java.lang.Object==
方法说明
- ==wait()== :使当前线程等待 应用前线程必须有使用有 同步锁。 等待其他线程使用 同步锁 调用 notify()/notifyAll()方法 使其唤醒,然后线程等待直到它重新获取同步锁才恢复执行(被挂起 同步锁 会被释放)
- ==notify()== :唤醒正在等待的线程 唤醒正在此 同步锁 上等待的单个线程。如果有多个线程正在等待该对象,则选择其中一个被唤醒(选择是任意的)
- ==notifyAll()== :唤醒正在等待的所有线程 唤醒正在此 同步锁 上等待的所有线程
public class WakeThread {
/**
* 线程唤醒
*/
public static void main(String[] args) {
/** 测试原理
* 创建多个线程,通过不同线程相互交互控制 同步锁的应用
* 1. 创建三个线程分别为A,B,C,三个线程打印他们自己的执行过程
* 2. 创建一个对象 充当 同步锁的使用
* 3. 最先获取 同步锁 A进行 wait() 挂起等待 notify()/notifyAll()唤醒
*/
// 同步锁
final Object synObj = new Object();
Runnable t1 = ()->{
System.out.println("T1 启动");
synchronized (synObj) {
System.out.println("T1 获取 同步锁");
try {
Thread.sleep(3000);
System.out.println("T1 wait()时挂起");
/**
* T1 挂起wait() 等待唤醒
*/
synObj.wait();
System.out.println("T1 被其他线程唤醒后重新获取SynObj对象监视器执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("T1 结束");
};
Runnable t2 = ()->{
System.out.println("T2 启动");
synchronized (synObj) {
System.out.println("T2 获取 同步锁");
/**
* T2 唤醒该 同步锁 中的一个单线程
*/
synObj.notify();
System.out.println("T2 执行 notify()方法 唤醒");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("T2 结束");
};
Runnable t3 = ()->{
System.out.println("T3 启动");
synchronized (synObj) {
System.out.println("T3 获取 同步锁");
/**
* T3 唤醒该 同步锁 中的所有线程
*/
synObj.notifyAll();
System.out.println("T3 执行 notifyAll()方法 唤醒");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("T3 结束");
};
new Thread(t1,"T1").start();
new Thread(t2,"T2").start();
new Thread(t3,"T3").start();
}
}
/* 控制台结果
T1 启动
T3 启动
T2 启动
T1 获取 同步锁
T1 wait()时挂起
T2 获取 同步锁
T2 执行 notify()方法 唤醒
T2 结束
T3 获取 同步锁
T3 执行 notifyAll()方法 唤醒
T3 结束
T1 被其他线程唤醒后重新获取SynObj对象监视器执行
T1 结束
*/
T1 被唤醒后并非马上执行,因 T2与T3 争夺 同步锁,因此 1T 获取 同步锁 后才能继续执行
# 线程礼让
==yield()==静态方法 它可以让当前正在执行的线程暂停,但它不会堵塞线程该线程,它只是将线程转入就绪状态
注意: A线程执行 yield()方法 礼让后 ,以下可能会出现优先级的问题
- A与B的 优先级 相同 :A,B线程 依旧会有争夺CPU资源
- A的优先级更高:A线程可能不但礼让后还抢占CPU资源的
- B的优先级更高:A线程会老老实实的 礼让 B线程
/** 礼让线程
* 说明1:向调度程序提示当前线程愿意放弃其当前对处理器的使用。调度程序可以随意忽略此提示。
* Yield 是一种启发式尝试,旨在改善线程之间的相对进展,否则会过度使用 CPU。
* 它的使用应与详细的分析和基准测试相结合,以确保它实际上具有预期的效果。
* 说明2:将指定线程暂停,不会堵塞线程,重新分配到线程的就绪状态
*/
public class YieldTest extends Thread{
public YieldTest(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0 ; i < 50 ; i++) {
System.out.println(getName()+" : "+i);
// 使当前线程 礼让
if (i==20) {
System.out.println(getName()+"礼让");
/**
* 设置 当前线程礼让
*/
Thread.yield();
}
}
}
/** 测试原理
* 创建两个线程分别让他们执行到特定的时刻进行礼让
* 1. 创建线程A和线程B ,且A,B线程有循环 50次
* 2. A,B线程执行到 20 执行 yield() 使当前线程礼让
*/
public static void main(String[] args) {
YieldTest yt1 = new YieldTest("A");
YieldTest yt2 = new YieldTest("B");
yt1.start();
yt2.start();
}
}
# 线程优先级
每个线程都有自己的优先级,线程的优先级代表着该线程的重要性。多个处于就绪的线程就能体现优先级的作用!
Thread常量 | 值 |
---|---|
MAX_PRIORITY | 10 |
MIN_PRIORITY | 1 |
NORM_PRIORITY | 5 (默认值) |
==setPriority(int newPriority)==方法 对线程优先级的调整
**注意:**线程的优先级范围只能设置 0 - 10 整型范围
# 线程生命周期
线程具有生命周期,有7种分别为:出生状态、就绪状态、运行状态、休眠状态、阻塞状态、死亡状态
Windows操作系统中,会为每个线程分配一小段CPU时间片,一旦CPU时间片结束会切换到下一线程
周期的说明:
- 出生/创建 状态(New): 线程创建后到 线程的start()方法前
- 就绪状态(Runnable): 可执行状态,进入线程池等待获取CPU的使用权,获取使用权在进入进入运行状态
- 运行状态(Running): 已经获取CPU的使用权,执行run()方法,没有意外 线程则一直运行到结束
- 阻塞状态(Blocked): 线程可能处于某种原因放弃/CPU的使用权 (停止运行),会直到结束进入线程池回到就绪状态,堵塞的情况分为:
- 等待堵塞: 线程 IO方法堵塞 ,JVM会把线程放入 等待池中
- 同步堵塞: 在线程获取 对象同步锁前,该 同步对象的同步锁 被别的线程占用 未释放锁 ,JVM会将线程放入 锁池中
- 其他堵塞: 线程执行 sleep()/join()方法,或用户 输入/输出,JVM会将线程至为堵塞状态
- 死亡状态(Dead): 线程方法跑完/线程异常/stop()方法停止=,则进入死亡状态
再次进入运行状态:
- 线程调用notify()方法(唤醒线程)
- 线程调用notifyAll()方法(唤醒线程)
- 线程调用interrupt()方法(中断线程)
- 线程的休眠时间结束
- 输入/输出 结束
导致死锁的
死锁是指两个或多个线程无限期地等待对方持有的资源而导致的一种阻塞现象
# 线程同步
多线程执行程序,会出现线程抢资源的现象,该现象会导致数据脏读!为了防止多线程的冲突,JAVA提供了线程同步的机制来防止资源抢占的问题!
# synchronized 关键字 隐式锁
synchronized
关键字采用定时只允许一个线程访问共享资源 (道理跟上排队上厕所一样
- 同步对象 (又称同步监听器) 可以任意
- 不可实例本身对象 (测试创建其他线程对象呢?)
- 同步代码块中的线程跑完才会释放代码块
# 同步块
每个对象都有标志位,它具有0和1两个值。0代表同步块中在运行其他线程;1代表该线程能被同步块执行,执行中途并将Object对象的标志位设置为0,防止其他线程执行同步块中的代码。(一个线程运行到同步块时首先检查该对象的标志位)
// Object 同步锁
synchronized(Object){
···
}
//Object:任意对象,仅作为同步锁(相当于一把锁,多人使用的锁)
# 同步方法
方法 前面修饰 synchronized关键字 形成同步方法 某对象调用同步方法时,该对象的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为synchronized,否则会报错!
# Lock 接口 显示锁
ReentrantLock
显示锁
ReentrantLock
相比 synchronized
更加直观
构造方法 ReentrantLock()
ReentrantLock(boolean fair)
fair: 公平锁
方法
返回 | 方法 | 说明 |
---|---|---|
int | getHoldCount() | 查询当前线程对锁的停止数量 |
int | getQueueLength() | 获取锁的线程数 估数 |
int | getWaitQueueLength(Condition condition) | 获取与此锁相关条件等待的线程 |
boolean | hasQueuedThread(Thread thread) | 查询指定线程是否获取锁 |
boolean | hasQueuedThreads() | 查询是否有线程等待锁 |
boolean | hasWaiters(Condition condition) | 查询是否有相关条件等待的锁 |
boolean | isFair() | 是否为锁的公平,启动则true |
boolean | isHeldByCurrentThread() | 查询锁是否是当前线程持有 |
boolean | isLocked() | 查询锁是否有线程持有 |
void | lock() | 锁定锁(上锁) |
void | lockInterruptibly() | 锁定锁 |
String | toString() | 返回标识锁的字符串内容 |
boolean | tryLock() | 判断锁是否存在 |
boolean | tryLock(long timeout, TimeUnit unit) | 判断锁是否存在,指定时间超时返回false |
void | unlock() | 释放锁(解锁) |
# 同步锁总结
同步锁解决方法:同步代码块、同步方法、Lock接口
同步代码块 和 同步方法 ,是隐式 获取/释放 锁
Lock接口 获取/释放 锁是显示的,自行操作
Lock接口 较灵活,可不用在同一 代码块/方法 中 进行 获取/释放 锁
Lock接口 获取锁后 ,一定要释放锁
Lock 默认是非公平锁,释放锁后可以继续抢锁;如果是 公平锁会根据等待时间进行分配锁(等待时间越长获锁几率越高!
# 线程池
Java线程池中是对线程的一种管理机制 , 能够有效的管理和复用线程 , 能够提高多线程的性能和效率 (线程的集合)
频繁多线程操作会影响效率。反复的 创建 、关闭 线程会需要大量时间!可减少时间 和 资源的浪费!
主要参数
- corePoolSize 最大管理线程数
- maximumPoolSize 最大线程数
- keepAliveTime 线程空闲时间
- unit 时间单位
线程池原理图
# 缓存线程池 newCachedThreadPool
newCachedThreadPool 缓存线程池,缓存线程时长默认心跳存活60秒
当一个线程添加到池中,如果该线程在 60秒内 未被使用,则移出该线程
特点:
- 无长度限制
- 自动扩容空间
# 定长线程池 newFixedThreadPool
newFixedThreadPool 固定大小的线程池,可以指定线程池的大小
ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory);
特点:
- 自定 固定 长度
- 无闲线程 空间未满 自动扩容
- 无闲线程 空间已满 等待空闲
# 单线程线程池 newSingleThreadExecutor
newSingleThreadExecutor 单个单线程线程池,只有一个线程的线程池
特点:
- 只有一个线程
- 无闲线程 等待
# 定时线程池 newScheduledThreadPool
newScheduledThreadPool 周期性任务定长线程池,
该线程池可用于周期性去执行任务,通常用于周期性的同步数据
- 可指定长度
- 无闲线程 空间未满 自动扩容
- 无闲线程 空间已满 等待空闲
- 定时执行、周期执行
# 代码索引
# File操作
public class Demo {
public static void main(String[] args) {
//实例对象
Thread a = new MyThreadA();
Thread b = new MyThreadB();
/**其他方法测试*/
System.out.println("==========");
System.out.println("a.getId():"+a.getId());
System.out.println("a.getName():"+a.getName());
System.out.println("a.getPriority():"+a.getPriority());
System.out.println("a.getState():"+a.getState());
System.out.println("a.isAlive():"+a.isAlive());
System.out.println("a.isInterrupted():"+a.isInterrupted());
System.out.println("a.toString():"+a.toString());
System.out.println("==========");
//执行线程(双线程执行,同时执行)
/**线程A*/
a.start();
/**线程B*/
b.start();
/**
以下代码为运行a对象的run()方法再执行b对象run()方法
a.run();
b.run();
*/
}
}
class MyThreadA extends Thread{
@Override
public void run() {
for (int i = 0; i < 26; i++) {
System.out.print("A:"+i);
/**休眠1秒(等待)*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyThreadB extends Thread{
@Override
public void run() {
for (char i = 'a'; i < 'z'; i++) {
System.out.println("B:"+i);
/**休眠1秒(等待)*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**运行结果
==========
a.getId():13
a.getName():No.1
a.getPriority():5
a.getState():NEW
a.isAlive():false
a.isInterrupted():false
a.toString():Thread[No.1,5,main]
==========
B:a
A:0
B:b
A:1
B:c
A:2
A:3
B:d
B:e
A:4
A:5
B:f
A:6
B:g
A:7
B:h
A:8
B:i
B:j
A:9
A:10
B:k
A:11
B:l
A:12
B:m
B:n
A:13
A:14
B:o
B:p
A:15
B:q
A:16
B:r
A:17
B:s
A:18
A:19
B:t
B:u
A:20
A:21
B:v
A:22
B:w
B:x
A:23
B:y
A:24
A:25
*/
# Runnable操作
public class MainStartRunnable {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable() , "A");
Thread t2 = new Thread(new MyRunnable() , "B");
Thread t3 = new Thread(new MyRunnable() , "C");
t.start();
t2.start();
t3.start();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0 ; i < 10 ; i++) {
System.out.println(Thread.currentThread().getName()+" : "+i);
}
}
}
/*
B : 0
A : 0
A : 1
A : 2
A : 3
A : 4
A : 5
A : 6
A : 7
A : 8
A : 9
B : 1
B : 2
B : 3
B : 4
B : 5
B : 6
B : 7
B : 8
B : 9
C : 0
C : 1
C : 2
C : 3
C : 4
C : 5
C : 6
C : 7
C : 8
C : 9
*/
# Callable操作
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable callable = new MyCallable();
FutureTask<Integer> future = new FutureTask<>(callable);
new Thread(future).start();
System.out.println("线程返回 : "+future.get());
System.out.println("堵塞测试!!!");
}
static class MyCallable implements Callable<Integer>{
int num = 0;
//返回的方法
@Override
public Integer call() throws Exception {
for (int i = 1 ; i <= 100 ; i++) {
num += i;
System.out.println(Thread.currentThread().getName()+" : "+i);
}
return num;
}
}
}
/*
Thread-0 : 1
Thread-0 : 2
Thread-0 : 3
····
Thread-0 : 100
线程返回 : 5050
*/
# synchronized安全线程
public class Demo {
public static void main(String[] args) {
Runnable t = new Ticket();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
static class Ticket implements Runnable{
private int count = 10;
private final Object o = new Object();
@Override
public void run() {
while (true){
synchronized (o){
if (count > 0){
//如果synchronized套在这里 , 多线程会错读
System.out.println(Thread.currentThread().getName()+" : "+ --count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
}
/*
Thread-2 : 9
Thread-2 : 8
Thread-2 : 7
Thread-0 : 6
Thread-1 : 5
Thread-0 : 4
Thread-2 : 3
Thread-0 : 2
Thread-1 : 1
Thread-0 : 0
堵塞测试!!!
*/
# synchronized方法安全线程
public class Demo2 {
public static void main(String[] args) {
Runnable t = new Ticket();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
static class Ticket implements Runnable{
int count = 10;
@Override
public void run() {
while (true){
if (sell()){
break;
}
}
}
private synchronized boolean sell() {
if (count > 0){
System.out.println(Thread.currentThread().getName()+" : "+ --count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
return true;
}
}
}
/*
Thread-0 : 9
Thread-0 : 8
Thread-0 : 7
Thread-0 : 6
Thread-0 : 5
Thread-0 : 4
Thread-3 : 3
Thread-3 : 2
Thread-1 : 1
Thread-1 : 0
* */
# ReentrantLock安全线程
import java.util.concurrent.locks.ReentrantLock;
public class Demo3 {
public static void main(String[] args) {
Runnable lockTest = new LockTest();
new Thread(lockTest).start();
new Thread(lockTest).start();
new Thread(lockTest).start();
new Thread(lockTest).start();
}
static class LockTest implements Runnable{
//显式锁
static ReentrantLock l = new ReentrantLock(true);
int count = 10;
@Override
public void run() {
while (true){
l.lock();
if (sell()){
break;
}
if (count == 5){
test();
}
l.unlock();
}
l.unlock();
System.out.println("结束 : "+l.tryLock());
}
private void test() {
System.out.println(l.toString());
System.out.println(l.getHoldCount());
System.out.println(l.getQueueLength());
}
private boolean sell() {
if (count > 0){
System.out.println(Thread.currentThread().getName()+" : "+ --count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
return true;
}
}
}
/*
Thread-0 : 9
Thread-3 : 8
Thread-2 : 7
Thread-1 : 6
Thread-0 : 5
java.util.concurrent.locks.ReentrantLock@47ee0a89[Locked by thread Thread-0]
1
3
Thread-3 : 4
Thread-2 : 3
Thread-1 : 2
Thread-0 : 1
Thread-3 : 0
结束 : true
结束 : false
*/
# 线程优先级
import javax.swing.*;
import java.awt.*;
public class PriorityBookTest extends JFrame {
private Container c = getContentPane();
private JProgressBar
jp1 = new JProgressBar(),
jp2 = new JProgressBar(),
jp3 = new JProgressBar(),
jp4 = new JProgressBar();
private Thread
threadA = null,
threadB = null,
threadC = null,
threadD = null;
public PriorityBookTest(){
super("线程优先级");
setBounds(300 , 230 ,100,150);
setLayout(new FlowLayout());
setVisible(true);
threadA = new Thread(newThread(c , jp1));
threadB = new Thread(newThread(c , jp2));
threadC = new Thread(newThread(c , jp3));
threadD = new Thread(newThread(c , jp4));
setPriority("A" , 10 , threadA);
setPriority("B" , 7 , threadB);
setPriority("C" , 4 , threadC);
setPriority("D" , 1 , threadD);
}
private static Thread newThread(Container c , JProgressBar jp){
c.add(jp);
jp.setStringPainted(true);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int count = 0 ;
while (count <= 100){
jp.setValue(count++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
return thread;
}
public static void setPriority(String threadName , int priority , Thread t){
//设置进程优先级、名,启动
t.setPriority(priority);
t.setName(threadName);
t.start();
}
public static void main(String[] args) {
new PriorityBookTest();
}
}
/*
执行结果 : 窗体展示 进度条
*/
# 缓存线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//缓存线程池
public class Demo1 {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
//执行任务
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 1");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 2");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 3");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 4");
}
});
}
}
/*
pool-1-thread-3 : 3
pool-1-thread-2 : 2
pool-1-thread-1 : 1
pool-1-thread-1 : 4
*/
# 定长线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//定长线程池
public class Demo2 {
public static void main(String[] args) {
ExecutorService exception = Executors.newFixedThreadPool(2);
exception.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 1");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
exception.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 2");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
exception.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 3");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
exception.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 4");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
/*
pool-1-thread-1 : 1
pool-1-thread-2 : 2
pool-1-thread-2 : 3
pool-1-thread-1 : 4
*/
# 单线程线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//单线程线程池
public class Demo3 {
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" : 3");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
/*
pool-1-thread-1 : 1
pool-1-thread-1 : 2
pool-1-thread-1 : 3
*/
# 周期性任务定长线程池
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
//周期性任务定长线程池
public class Demo4 {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/**定时执行
* 参数1. 线程
* 参数2. 延时时长值
* 参数3. 时长单位
*/
service.schedule(new Runnable() {
@Override
public void run() {
System.out.println("延时2s , 执行的程序");
}
} , 2 , TimeUnit.SECONDS);
/**周期执行
* 参数1. 线程
* 参数2. 延时时长值
* 参数3. 周期间隔时长值
* 参数4. 时长单位
*/
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("延时3s 执行周期间隔2s 的循环程序");
}
} , 3 , 2 , TimeUnit.SECONDS);
}
}
/*
延时2s , 执行的程序
延时3s 执行周期间隔2s 的循环程序
延时3s 执行周期间隔2s 的循环程序
延时3s 执行周期间隔2s 的循环程序
·····
*/