本文介绍: 2、进程&线程2.1进程与线程进程:进程是代码在数据集合上的一次运行活动,是系统资源分配和调度的基本单位。线程:线城是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。
1、前言
学习并发
2、进程&线程
2.1进程与线程
进程:
线程:
2.2线程与进程的比较
进程与线程相⽐:
量
线程和进程的区别(GPT说)
4.
执⾏顺序:由于线程是在进程内部运⾏的,因此它们的执⾏顺序可能会受到⼀些限制。例如,在Java中, 线程的调度通常是由JVM进⾏控制的,⽽且可能⽆法精确地控制线程的执⾏顺序。相⽐之下,进程之间的 执⾏顺序通常是可以完全控制的。
执⾏顺序:由于线程是在进程内部运⾏的,因此它们的执⾏顺序可能会受到⼀些限制。例如,在Java中, 线程的调度通常是由JVM进⾏控制的,⽽且可能⽆法精确地控制线程的执⾏顺序。相⽐之下,进程之间的 执⾏顺序通常是可以完全控制的。
2.3、并发与并行
2.4应用
以调⽤⽅⻆度来讲,如果
2.4.1异步调⽤:
1) 设计
2) 结论
tomcat 的⼯作线程
2.4.2多线程提升效率
但如果是四核 cpu,各个核⼼分别使⽤线程 1 执⾏计算 1,线程 2 执⾏计算 2,线程 3 执⾏计算 3, 那么 3 个 线程是并⾏的,花费时间只取决于最⻓的那个线程运⾏的时间,即 11ms 最后加上汇总时间只会花费 12ms
这样可以最⼤限度地利⽤ CPU 资源,从⽽提⾼程序的执⾏效率。
当然,多线程也存在⼀些缺点,⽐如线程之间的协调和通信会增加额外开销,如果线程数量过多也会造成资源争 夺和系统负载过重的问题。因此,在实际应⽤中需要根据具体情况进⾏合理的线程管理和调度,避免出现不必要 的问题。
public class aa extends Thread {
public static void main(String[] args) {
Thread t = new Thread() {
@Override
public void run() {
System.out.println("通过Thread⽅式创建线程");
}
};
t.run();
//t.start();
}
}
加星:继承Thead类,重写run方法,调用start()方法启动线程。
public class ThreadTest {
/**
* 继 承Thread类
* /
public static class MyThread extends Thread {
@Override
public void run () {
System . out . println ( "This is child thread" ) ;
}
}
public static void main ( String [] args) {
MyThread thread = new MyThread ();
thread .start();
}
}
public class aa extends Thread {
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("使⽤Thread配合Runnable创建线程");
}
};
//创建线程对象
Thread thread = new Thread(r);
//启动线程
thread.start();
}
}
⼿动简化:
public class RunnableTask implements Runnable {
public void run () {
System . out . println ( "Runnable!" ) ;
}
public static void main ( String [] args) {
RunnableTask task = new RunnableTask ();
new Thread ( task ) .start();
}
}
创建线程⽅法3:FutureTask 配合 Thread(了解)
Thread与Runnble的关系
看Thread类的源码:
再看Runnbale接⼝的源码:
中的run()⽅法。
因此,Thread与Runnable之间的关系是:
线程并执⾏Runnable中的run()⽅法。
public class CallerTask implements Callable < String > {
public String call () throws Exception {
return "Hello,i am running!" ;
}
public static void main ( String [] args) {
/ /创建异步任务
FutureTask < String > task = new FutureTask < String > ( new CallerTask ());
/ /启动线程
new Thread ( task ) .start();
try {
/ /等 待 执 ⾏ 完 成 ,并获取返回结果
String result = task . get();
System . out . println ( result) ;
} catch ( InterruptedException e ) {
e . printStackTrace ();
} catch ( ExecutionException e ) {
e . printStackTrace ();
}
}
}
思考:
法?
程的效果。
观察多个线程同时运⾏
多个线程同时运⾏是指多个线程在同⼀时刻并发地进⾏执⾏。
●
线程是交替执⾏的
有⾃⼰的执⾏路径和执⾏状态,可以在不同的 CPU 核⼼上同时运⾏。
要理解多个线程同时运⾏,需要从计算机的硬件和操作系统的⻆度来看待。现代计算机通常包含多个 CPU 核⼼或者是⽀持超线程技术的 CPU,这些 CPU 能够并发处理多个指令流。当有多个线程需要执 ⾏时,操作系统会将这些线程分配到不同的 CPU 核⼼或者是时间⽚中,让它们同时运⾏。同时,由于 每个线程都有⾃⼰的代码执⾏路径和堆栈,所以它们之间不会相互⼲扰,可以独⽴地执⾏各⾃的任务。
3.2.查看进程线程的⽅法
linux系统
Java程序
3.3.线程运⾏原理
栈与栈帧
下⾯原因会导致线程上下⽂切换
3.4线程有哪些常⽤的调度⽅法?
线程等待与通知
情况才会返回 :
- wait(long timeout) :这个⽅法相⽐ wait() ⽅法多了⼀个超时参数,它的不同之处在于,如果线 程A调⽤共享对象的wait(long timeout)⽅法后,没有在指定的 timeout ms时间内被其它线程唤 醒,那么这个⽅法还是会因为超时⽽返回。
- wait(long timeout, int nanos),其内部调⽤的是 wait(long timout)函数。
- 上⾯是线程等待的⽅法,⽽唤醒线程主要是下⾯两个⽅法:notify() : ⼀个线程A调⽤共享对象的 notify() ⽅法后,会唤醒⼀个在这个共享变量上调⽤ wait 系列⽅法后被挂起的线程。 ⼀个共享变量上可能会有多个线程在等待,具体唤醒哪个等待的线程 是随机的。
- notifyAll() :不同于在共享变量上调⽤ notify() 函数会唤醒被阻塞到该共享变量上的⼀个线程,
- notifyAll()⽅法则会唤醒所有在该共享变量上由于调⽤ wait 系列⽅法⽽被挂起的线程。
- Thread类也提供了⼀个⽅法⽤于等待的⽅法:
- join():如果⼀个线程A执⾏了thread.join()语句,其含义是:当前线程A等待thread线程终⽌之
- 后才 从thread.join()返回。
线程休眠
- sleep(long millis) :Thread类中的静态⽅法,当⼀个执⾏中的线程A调⽤了Thread 的sleep⽅法 后,线程A会暂时让出指定时间的执⾏权,但是线程A所拥有的监视器资源,⽐如锁还是持有不让 出的。指定的睡眠时间到了后该函数会正常返回,接着参与 CPU 的调度,获取到 CPU 资源后就 可以继续运⾏。
让出优先权
线程中断
继续往下执⾏。
- boolean isInterrupted() ⽅法: 检测当前线程是否被中断。
- boolean interrupted() ⽅法: 检测当前线程是否被中断,与 isInterrupted 不同的是,该⽅法如 果发现当前线程被中断,则会清除中断标志
1. start和run
调⽤run
public static void main(String[] args) {
//创建线程
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug(Thread.currentThread().getName());
FileReader.read(Constants.MP4_FULL_PATH);
}
};
//运⾏线程
t1.run();
log.debug("do other things ...");
}
程序在 t1 线程运⾏, FileReader.read() ⽅法调⽤是异步的
start()⽅法会为线程创建⼀个新的执⾏路径,并在该路径上调⽤run()⽅法。如果直接调⽤run()⽅法,则不会创建新的执⾏路径,⽽是在当前线程上执⾏run()⽅法,这样就失去了 多线程的意义。
2. sleep和yield
让当前线程进⼊休眠,休眠时CPU的时间⽚会让给其他线程
提示线程调度器让出当前线程对CPU的使⽤
线程优先级
⽤
案例:防⽌CPU占⽤100%
sleep实现
CPU的使⽤权给其他程序
while(true) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
wait实现
加synchronized锁
synchronized(锁对象) {
while(条件不满⾜) {
try {
锁对象.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
// do sth...
}
条件变量实现
lock.lock();
try {
while(条件不满⾜) {
try {
条件变量.await();//当前线程休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// do sth...
} finally {
lock.unlock();
}
3. join
static int r = 0;
public static void main(String[] args) throws InterruptedException {
test1();
}
private static void test1() throws InterruptedException {
log.debug("开始");
Thread t1 = new Thread(() -> {
log.debug("开始");
sleep(1);
log.debug("结束");
r = 10;
});
t1.start();
log.debug("结果为:{}", r);
log.debug("结束");
}
结果是:开始..开始..结果为0..结束..结束…..
分析⼀下
解决⽅法
⽤ sleep ⾏不⾏?为什么?
⽤ join⽅法呢(同步)
join⽅法是让等待当前线程执⾏完才继续向下执⾏
static int result = 0;
private static void test1() throws InterruptedException {
log.debug("开始");
Thread t1 = new Thread(() -> {
log.debug("开始");
sleep(1);
log.debug("结束");
result = 10;
}, "t1");
t1.start();
t1.join();
log.debug("结果为:{}", result);
}
输出:
t1线程启动后,t1线程调⽤了join⽅法,所以主线程需要等待t1线程执⾏完之后才能执⾏
同步怎么理解?
以调⽤⽅⻆度来讲,
●
需要等待结果返回才能继续运⾏就是同步;
需要等待结果返回才能继续运⾏就是同步;
●
不需要等待结果返回就能继续运⾏就是异步
不需要等待结果返回就能继续运⾏就是异步
join⽅法例题:
private static void test2() throws InterruptedException {
Thread t1 = new Thread(() -> {
sleep(1);
r1 = 10;
});
Thread t2 = new Thread(() -> {
sleep(2);
r2 = 20;
});
t1.start();
t2.start();
long start = System.currentTimeMillis();
log.debug("join begin");
t1.join();
log.debug("t1 join end");
t2.join();
log.debug("t2 join end");
long end = System.currentTimeMillis();
log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
}
答案是2s
- 第⼀个 join:等待 t1 时, t2 并没有停⽌, ⽽在运⾏
- 第⼆个 join:1s 后, 执⾏到此, t2 也运⾏了 1s, 因此也只需再等待 1s
那如果改变两个join的位置呢?
答案也是2s
看流程图
t1的join⽅法在前⾯时,主线程异步运⾏t1,t2两个线程执⾏,调⽤t1的join⽅法后,t2线程需要等
待t1线
程执⾏完毕,但同时t2线程也在运⾏,t1线程运⾏结束等待t2线程运⾏结束,这时只需要再等待1s
就可,
t2线程已经运⾏了1s,总时间2s
t2的join⽅法在前⾯,同理,调⽤t2的join⽅法,t1线程等待t2线程运⾏结束的同时也在运⾏,所以
t2线程
执⾏完毕后就可以继续向下运⾏,总时间2s
等待多个线程的调度
并⾏执⾏,多个线程会同时运⾏,最终只会消耗时间久的join的时间
有时效的join
线程执⾏会导致join提前结束。
如果开启的t1线程⾥休眠2秒,join1.5秒,那主线程不会等待t1线程执⾏完就会执⾏。
如果开启的t1线程⾥休眠2秒,join3秒,那主线程会随着t1线程执⾏完就提前执⾏(⽆需等join
完)
4.interrupt
打断 sleep,wait,join的线程
,这⼏个⽅法都会使线程进⼊阻塞
,这⼏个⽅法都会使线程进⼊阻塞
1、打断sleep的线程,会清空打断状态
private static void test1() throws InterruptedException {
Thread t1 = new Thread(()->{
sleep(1);
}, "t1");
t1.start();
sleep(0.5);
t1.interrupt();
log.debug(" 打断状态: {}", t1.isInterrupted());
}
总结:
2、打断正常运⾏的线程, 不会清空打断状态
private static void test2() throws InterruptedException {
Thread t2 = new Thread(()->{
while(true) {
Thread current = Thread.currentThread();
boolean interrupted = current.isInterrupted();
if(interrupted) {
log.debug(" 打断状态: {}", interrupted);
break;
}
}
}, "t2");
t2.start();
sleep(0.5);
t2.interrupt();
}
3.打断park的线程
private static void test3() {
Thread t1 = new Thread(() -> {
log.debug("park...");
LockSupport.park();
log.debug("unpark...");
log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
}, "t1");
t1.start();
sleep(0.5);
t1.interrupt();
}
打断park线程总结
式。
在⼀个线程T1中如何优雅的终⽌线程T2?这⾥的优雅指的是给T2⼀个料理后事的机会
让整个程序都停⽌)
两阶段终⽌模式的实现
1.利⽤interrupt
interrupt 可以打断正在执⾏的线程,⽆论这个线程是在 sleep,wait,还是正常运⾏
模拟打断
class TPTInterrupt {
private Thread thread;
public void start(){
thread = new Thread(() -> {
while(true) {
Thread current = Thread.currentThread();
if(current.isInterrupted()) {
log.debug("料理后事");
break;
}
try {
Thread.sleep(1000);
log.debug("将结果保存");
} catch (InterruptedException e) {
current.interrupt();
}
// 执⾏监控操作
}
},"监控线程");
thread.start();
}
public void stop() {
thread.interrupt();
}
}
调⽤:
TPTInterrupt t = new TPTInterrupt();
t.start();
Thread.sleep(3500);
log.debug("stop");
t.stop();
输出:
主线程启动了t线程后进⼊休眠,在这期间t线程⽆法“料理后事”,每隔⼀秒将结果保存,主线程休眠结束
后调⽤
stop⽅法,打断t线程,结束
2.利⽤打断标记
// 停⽌标记⽤ volatile 是为了保证该变量在多个线程之间的可⻅性
// 我们的例⼦中,即主线程把它修改为 true 对 t1 线程可⻅
class TPTVolatile {
private Thread thread;
private volatile boolean stop = false;
public void start(){
thread = new Thread(() -> {
while(true) {
Thread current = Thread.currentThread();
if(stop) {
log.debug("料理后事");
break;
}
try {
Thread.sleep(1000);
log.debug("将结果保存");
} catch (InterruptedException e) {
}
// 执⾏监控操作
}
},"监控线程");
thread.start();
}
public void stop() {
stop = true;
thread.interrupt();
}
}
调⽤:
TPTVolatile t = new TPTVolatile();
t.start();
Thread.sleep(3500);
log.debug("stop");
t.stop();
输出:
不推荐使⽤的⽅法
3.5主线程与守护线程
完,也会强制结束。
注意:
后,不会等待它们处理完当前请求
3.6线程有几种状态
在
Java
中,线程共有六种状态:
Java
中,线程共有六种状态:
线程在⾃⾝的⽣命周期中, 并不是固定地处于某个状态,⽽是随着代码的执⾏在不同的状态之间进⾏
⾏【运⾏状态】指获取了 CPU 时间⽚运⾏中的状态
【阻塞状态】
切换,进⼊【阻塞状态】
不会考虑调度它们
线程的六种状态
从Java API层⾯描述,线程有6种状态
●
NEW是线程创建好但还没运⾏
NEW是线程创建好但还没运⾏
●
RUNNABLE是运⾏状态
RUNNABLE是运⾏状态
●
BLOCKED是线程阻塞状态
BLOCKED是线程阻塞状态
●
WAITING是等待状态
WAITING是等待状态
●
TERMINATED线程终⽌状态
TERMINATED线程终⽌状态
线程的六种状态状态(⼆哥)
线程的状态转换图
原文地址:https://blog.csdn.net/qq_64948664/article/details/134753721
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_38722.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。