wix做网站教程,如何重新做公司网站,wordpress 目录样式,广州市公司网站建设平台1.线程是什么
#xff08;shift F6#xff09;改类名
1.1.并发编程是什么
#xff08;1#xff09;当前的CPU#xff0c;都是多核心CPU
#xff08;2#xff09;需要一些特定的编程技巧#xff0c;把要完成的仍无#xff0c;拆解成多个部分#xff0c;并且分别让…1.线程是什么
shift F6改类名
1.1.并发编程是什么
1当前的CPU都是多核心CPU
2需要一些特定的编程技巧把要完成的仍无拆解成多个部分并且分别让他们在不同的cpu上运行。 要不然就会编程一核有难多核围观的场景 并发编程指的是并行并发
3通过多进程编程的模式就可以达到并发编程的效果。 因为进程可以被调度到不同的cpu上面运行 此时就可以把多个cpu核心核心都很好的利用起来 (4)虽然多进程编程可以解决上述问题但是带来了新的问题。
1.2.问题
1在编程过程中服务器开发的圈子李这种并发编程要能够给多个客户端提供服务。
如果同一时间来了很多客户端服务器如果只利用一个cpu核心工作速度会比较慢
2多搞几个厨师来炒菜这样就大幅的提高了效率
3一个比较好的做法就是每个客户端连上服务器服务器都创建一个新的进程给客户端提供服务这个客户端断开了服务器再把进程示范掉
如果服务器频繁有客户端来来去去服务器就需要频繁创建销毁进程。服务器响应速度会变慢
1.3.如何解决这个问题线程的引出
引入线程主要的出现就是为了解决上述进程太重量的问题
1线程thread也叫做轻量级进程创建销毁的开销更小。
2线程可以理解为进程的一部分一个进程中可以包含一个线程或者多个线程
3描述进程使用的是PCB这样的结构体事实上更严格的说一个PCB其实是描述一个进程的若干个PCB联合在一起是描述一个进程的。
4pcb中包括pid 内存指针 文件描述表 状态上下文优先级记账信息 tgid每一个线程所提供的pid是不一样的但是tgit是一样的所以我们可以用tgit来判断这个线程是不是在一个线程下面
5还要同一个进程的若干个线程这里的内存指针和文件描述表其实是同一个。
6状态上下文优先级记账信息每个线程有一组自己的属性
7同一个进程中的若干个线程之间是相同的内存资源和文件资源的。 线程之间可以互相访问
进程是系统资源分配的基本单位
线程是系统调度执行的基本单位
同一个进程包括N个线程线程之间是共用资源
只有你创建第一个线程的时候去进行资源的申请操作后序再创建线程都没有申请资源的过程了。
1.3.1并发编程
1在我们引入了进程以后那么我们就可以思考进程的作用是什么
2图解举例 3我们现在的计算机不都是好多核心所以我们可以用多个线程来对工作进行拆分 4由于成本很高而且电脑的核心也并不是特别的多所以我们引出了多线程编程。 相当于线程为进程分担了问题 5这时候就有同学提出问题是不是线程越多越好这当然不是因为线程的调度也是需要分配资源的合适的线程可以帮助你来更好的管理资源但是如果线程过多的化那么线程就会变慢。 6其中我们还要思考一个问题就是线程的调度资源到底花费到哪里 7其中多核CPU才能进行这种操作 8其中在线程不是太多的情况下也可能发生线程安全的问题。 1.4总结
总结为啥说线程更加轻量开销更小核心就在于创建进程可能包含多个线程这个过程中涉及到资源分配资源释放。
1.5线程于进程的关系以及相关问题
1.6关键面试题线程和进程的区 别
2.代码实现线程和进程、
线程本身是操作系统提供的。
操作系统提供了API让我们操作系统
JVM就对操作系统的api进行封装
线程这里提供了thread类实现了封装
2.1线程的代码实现
其中操作系统提供了api来对线程进行操作然而我们的编译器使用了JVMjava虚拟机来进行操作操作系统的api其中在java中我们使用的就是Thread类来对线程进行操作 2.1.1Thread 代码的基本实现 其中run方法是Thread中本来就有的方法 ,我们把他重写了
进入源代码 可以看到我们重写了run方法。
2.1.1.1注意事项
1上面的这段代码其实是创建了两个线程分别是main线程另一个就是t线程
2其中main是主线程也就是jvm在运行的时候就会创建出来。
3其中一个线程中至少包含一个进程然后再进程中至少包含一个线程在没有引入多并发编程之前我们运行的程序都是一个进程然后我们在一个线程下面编写代码。
4在上面的程序中就是一个进程然后进程的下面有两个线程分别是t线程然后是jvm生成的主线程mian
2.1.2线程的状况线程一直进行来进行分析
其中try catch来对其进行捕获是因为防止在其他线程或者什么东东调用正在休眠的线程这时候就会一直等下去也就是阻塞所以我们要用trycatch来进行处理
try {// 尝试执行这里的代码可能会抛出异常
} catch (ExceptionType1 e) {// 如果try块中的代码抛出了ExceptionType1类型的异常则执行这里的代码
} catch (ExceptionType2 e) {// 如果try块中的代码抛出了ExceptionType2类型的异常则执行这里的代码
} finally {// 无论是否发生异常finally块中的代码总是会被执行
} 代码整体实现
package thread;
class MyThread extends Thread{public void run(){while(true){System.out.println(HelloThread1);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Demo1 {public static void main(String[] args) {Thread t new MyThread();t.start();while(true){System.out.println(HelloThread1);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}其中main和t线程是并发执行的 其中我们要注意的一点就是sleep后面的休眠时间的单位是ms其中sleep的作用就是将这个停一下在方到系统上面的CPU上面进行执行
时间到了以后就会解除阻塞状态也就是。
它可以让我们的CPU的调度有休息可以更好的处理资源的调度
2.1.3线程的使用情况2.1.2中的代码
在运行的时候我们可以看到每秒钟打印一次
其中main可能t线程的前面
t线程也可能在main线程的后面
也就是谁抢上资源谁就进行输出
2.1.4其他一些关系线程的东西就一起来说明了
1 总的来说就是我们定义了一个线程的基本框架MyThread类其中在main方法中的Thread t new MyThread只是实例化这个对象而已也没有创建线程这时候的start是Thread中里面的方法只有在调用这个方法的时候才会使用我们实例化的线程框架来创建线程
通俗点说就是 2其中要注意的是 所以刚才写的代码就是线程的串行执行 2.2Thread的五种写法
2.2.1第一种创建一个类继承Thread方法
这个是我们一开始说的那个方法 2.2.2第二种创建一个类描述线程实现Thread的方法
这个方法实现线程的方式是比较好的方式
它能大大的降低耦合度
我们不同于第一种创建我们是实例化Thread然后把MyRunnable作为参数传入实例化的对象中作为参数 两种Thread的对比1和2种方法 2.2.3第三种创建 使用匿名内部类创建线程框架继承Thread类
代码实现
这个定义了一个匿名内部类来对,这个匿名内部类直接继承Thread类然后重写Thread的中的run方法然后最后t.star就可以了 总结 2.2.4第四种创建方式lambod表达式创建JDK8的新属性
这个方式可以理解为用函数式接口的方法
在Thread类中式没有抽象方法的但是在Thread中实现了Runnable接口里面有一个run抽象方法lambod表达式就会重写这个方法来做出线程的框架
相较于Thread的内部类来实现来说 lambad表达式只能用函数式接口来重写run但是比内部类实现来说方便许多匿名内部类实现的化比它麻烦一点但是它的扩展性比lamda表达式要好很多
注意的一点就是主线程一直在其他线程完成以后再执行的
代码实现 2.2.5第五种方法是实现Runnable重写run使用内部类 总结 2.3线程的几种其他用法
2.3.1给线程定义名字
1在线程的结尾来定义名字
代码示例
package thread;public class Demo6{public static void main(String[] args) {Thread t new Thread(()-{while (true){System.out.println(make name from Thread);try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}}},Frank);t.start();}
}2.4Catch中写的是什么Sleep的注意事项
1 2
其中我们要注意的就是在main方法中我们有两种方法来处理sleep
分别时 try catch 和Throws
用try catch 可以捕获异常然后程序员选则如何处理这个异常
用Throws是捕获的异常必须要优先处理
2.5小结 3线程的区别
线程分为分为前台线程和后台线程
前台线程就是这个线程不结束java程序
后台线程就是这前台线程结束那么他就结束了
4将进程设置为后台进程
代码实现
public class DaemonThreadExample {public static void main(String[] args) {// 创建一个线程Thread daemonThread new Thread(new Runnable() {Overridepublic void run() {while (true) {try {System.out.println(Daemon Thread is running...);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}});// 将线程设置为后台线程daemonThread.setDaemon(true);// 启动线程daemonThread.start();// 主线程执行完毕由于daemonThread是后台线程程序不会等待它执行完毕就会退出System.out.println(Main thread is exiting...);}
} 5.其他知识的扩充
1 6.如何让线程中断
我们可以定义一个布尔值的变量其中我们可以用布尔值来控制循环的开始和结束。
代码实现
其中要注意的是外部类成员是不会报错 2线程的中断 总结一下t线程在sleep状态时就像你的朋友决定去睡觉并且不想被打扰一样它是不会响应中断请求的。如果你想让它在需要的时候提前醒来你需要在编写代码时让它能够检查并响应中断请求。
6.1线程如何更好的中断 代码解析
首先我们要明白什么是线程中断。在Java中线程中断是一种协作机制允许一个线程请求另一个线程停止它正在做的事情。这通常是因为某种原因比如用户取消了操作或者系统需要释放资源。
Thread.currentThread().isInterrupted() 这个方法用来检查当前线程是否已经被其他线程中断。中断状态是一个标志当一个线程调用另一个线程的 interrupt() 方法时它会设置这个标志。
while (!Thread.currentThread().isInterrupted()) 这个循环的意思是“只要当前线程还没有被中断就继续执行循环里的代码。” 如果线程在循环内部被中断比如其他线程调用了它的 interrupt() 方法那么 isInterrupted() 方法会返回 true 循环条件变为 false 循环就会停止。
现在让我们看一个简单的例子
假设你正在煮一壶水并且你想在水开之前不断检查它。你可以把煮水的过程想象成一个线程的任务。如果突然有急事要离开你可能会想中断这个线程也就是停止检查水是否开了。
在这个例子中 while (!Thread.currentThread().isInterrupted()) 就像是你在不断地问自己“我是不是应该停止检查水是否开了” 只要你没有被中断也就是没有急事发生你就会继续检查。一旦你收到中断信号比如有人叫你你就会停止检查并去处理其他事情。
Thread.interrupt() 方法就像是有人按下了停止按钮告诉线程“你应该停止你正在做的事情了。” 而 isInterrupted() 方法就像是线程在回答“好的我已经收到停止的信号了。”
这时候当我们进行运行的时候会发现虽然我们返回了true想要中断但是却没有中断这是因为sleep会将false再修改回true这是为了能够让程序员更好的控制线程而不是让程序自己控制线程我们可以再catch中选择他是继续往下进行还是结束
图解 7线程的其他方法 详细图解
其要注意的就是前台线程结束后台线程不管如何都会结束而后台线程结束那么前台线程是不会结束的。 注意事项 3.Thread中的join方法线程的阻塞
3.1join方法的本质
1
图解 2join方法的本质是指的是使用了这个方法的线程就会阻塞
图解 所以main线程永远是最后进行执行的。
其中要注意的就是如果没有设置sleep就是哪个线程先用join那么哪个线程就先执行还有就是只有start了以后才能join如果休眠时间一样也按这种方式处理如果休眠时间不一样那么休眠间短的线程先执行然后再是休眠时间最长的最后再是main线程。
3.2代码示例
public class JoinExample {public static void main(String[] args) {Thread thread1 new Thread(() - {System.out.println(Thread 1 starting...);try {Thread.sleep(1000); // 模拟耗时操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread 1 ending...);});Thread thread2 new Thread(() - {System.out.println(Thread 2 starting...);try {Thread.sleep(1500); // 模拟耗时操作比线程1稍微长一些} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread 2 ending...);});thread1.start(); // 启动线程1thread2.start(); // 启动线程2try {thread1.join(); // 等待线程1完成thread2.join(); // 等待线程2完成} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Main thread continuing...); // 当两个子线程都完成后主线程继续执行}
}
3.3join最大等待时间
1. 概念 join方法可以理解为谁调用这个方法谁就会被阻塞然后等待这个线程运行结束以后然后恢复执行。
2.这个就相当于join等待不能一直等待我们可以规定一个时间来限制他。
图示(深度解析) 3.4sleep 和join 方法的区别
1sleep在java的库中是native方法也就是本地方法它的底层我们是看不到的
2通俗点来讲sleep是控制这个线程的休眠时间而不是两个代码的执行的间隔时间。
3sleep是根据时间戳来对其进行休眠时间的判定
3system.currentTimeMillis这个代码可以获得我们系统的时间戳
注意事项 4对于join方法来说这个就是真正的阻塞只有前面没有调用这个方法的线程执行结束这个阻塞才会恢复然后执行这个调用这个join方法的线程
4.引出线程安全问题为下一篇文章做基础
4.1引言
1我们之前提到过线程的状态其中我们也可以叫它为PCB状态其中linux 和windos系统linux系统有非常成熟的系统来操控PCB当然windos系统中也会有选项来对其进行操作只不过性能方面没有比linux更好罢了。
2其中在我们java的jdk中的jvm虚拟机中nb的大佬程序员都为我们封装好了这些东西来对其进行操作相较于C来说java方便太多C语言的特征是性能高稳定但是编写难度较高。
4.2 六种PCB状态梳理
1NEW状态
这个状态就是Thread线程的对象已经有了没有进行start系统内部的线程还没有创建。
2.Terminated状态
这个状态是Thread线程的对象有了也执行完毕然后被销毁最后还剩下一个Thread对象。
3Runnable状态就绪状态
这个指的是这个线程已经调度到了系统的CPU上面其中有两种情况。
第一种就是这个线程已经在CPU上面但是还没有执行
第二种就是这个线程已经在CPU上面进行执行了
我看了很多资料讲解的都不是很好他们将这两种状态分开了叫出了两种名称我认为其实没啥用因为都已经到CPU上面了已经不是人能决定的了而是全部由系统决定你就算再nb你能对系统进行操作吗所以这两种状态我都称之为就绪状态。
5.阻塞的三种状态讲解 最后一个状态我们在下一篇文章中进行讲解
打开idea的文件夹找到查看线程状态的软件来对阻塞进行讲解
可以看到join是死等join带有最大阻塞时间和sleep休眠是TIMD-WAITING是带有时间的阻塞。
这个的作用就是在你以后工作的时候来判断你的各个线程的状态来更好的开发项目 1线程不安全示例 相当于它会重复的对数据进行读取这是非常不好的。
我们可以进行串行执行 这样就好了
所以死锁问题就是这样产生的。
1为什么发生这种问题的简单原因。 2其中在上面的加到5000的情况下面还有一个情况就是两个加在一起小于5w的情况。
在多线程环境中每个线程都有自己的 CPU 缓存和工作内存。当一个线程修改了变量的值时这个变化不会立即反映到主内存中而是在适当的时机才会同步到主内存中。其他线程在读取这个变量的值时可能会直接从自己的 CPU 缓存或者工作内存中读取而不是从主内存中读取这就导致了可能读取到旧值的情况发生。