动画制作软件免费版,短视频seo搜索优化,太原网站优化步骤,竞价在什么网站上做目录
1、线程的引入
2、什么是线程
3、线程的基本特点
4、线程安全问题
5、创建线程
5.1 继承Thread类#xff0c;重写run
5.1.1 创建Thread类对象
5.1.2 重写run方法
5.1.3 start方法创建线程
5.1.4 抢占式执行
5.2 实现Runnable#xff0c;重写run【解耦合】★…目录
1、线程的引入
2、什么是线程
3、线程的基本特点
4、线程安全问题
5、创建线程
5.1 继承Thread类重写run
5.1.1 创建Thread类对象
5.1.2 重写run方法
5.1.3 start方法创建线程
5.1.4 抢占式执行
5.2 实现Runnable重写run【解耦合】★★★
6、知识拓展
6.1 拓展一名词解释——api
6.2 拓展二异常处理方式
6.3 拓展三名词解释——客户端服务器 6.4 拓展四高内聚低耦合
6.4.1 耦合
6.4.2 内聚 1、线程的引入
大家都知道当代CPU为多任务处理器具备多个核心而为了充分发挥CPU多核心的性能避免出现“一核有难多核围观”的情况“并发编程”就成为刚需。
而通过多进程的方式可以实现“并发编程”的效果。
虽然说多进程的方式可以实现“并发编程”但是要知道进程整体是一个比较“重量级”的概念如果频繁的创建与销毁开销是很大的。
尤其是对于服务器来说一个服务器会为多个客户端提供服务服务的客户多了进程的创建与销毁操作自然也会增多。
举个例子此时我们打开了百度的网页但是这时全国甚至全球会有大量的用户与我们进行相同的操作会有大量用户对服务器发送大量的请求大量的进行创建与销毁操作如果采用多进程方式的话开销是很大的。
为了解决上述问题引入一个轻量级的概念——线程thread。
2、什么是线程
线程thread又称为轻量级进程。
也就是说线程是一个轻量级的东西它的创建与销毁的开销要比进程小得多。
因此可以通过多线程的方式来实现“并发编程”。
3、线程的基本特点
上篇博客说到一个进程相当于一个要执行的任务。
而一个线程也相当于一个要执行的任务。
线程与进程的区别如下
进程包含线程每个进程中都会有一个或者多个线程。且至少有一个线程这个线程在进程创建时随进程一起创建称为主线程。进程是操作系统资源分配的基本单位每个进程都会分配一定的CPU资源、内存资源、硬盘(文件描述符表)资源、网络带宽资源.....。也就是说在进程创建时需要申请资源在进程销毁时需要释放资源。会增大系统开销而对于线程来说在进程内部管辖的多个线程之间会共享进程分配到的资源。对于线程只是在第一个线程创建时(随进程创建时创建的主线程)需要申请资源后续再创建的线程不需要进行资源申请操作。且只有所有的线程都销毁(进程销毁)时才会释放资源运行过程中销毁某个进程也不会释放资源。系统开销低进程和进程间每个进程分配到的资源都是各自独立的彼此之间互不干扰具有稳定性。进程内部的线程间会出现相互影响的情况具有“线程安全问题”。上文所讲的“进程调度”准确的来说其实是“线程调度”(当一个进程中只有一个线程时可以称为“进程调度”)。也就是说线程是CPU上调度执行的基本单位。如果一个进程中有多个线程那么这些线程是各自去CPU上调度执行的可能多个线程由1个核心执行(并发)也可能多个线程由多个核心同时执行(并行)也可能在不同的CPU上来回切换具体线程是怎么调度执行的由操作系统内部“调度器”自行完成程序猿感知不到也干预不了。每个线程都会有属于自己单独的调度相关的信息线程状态、线程上下文、线程优先级、线程记账信息。也就是说如果一个进程中有10个线程就会有10份这样的信息。但是一个进程中的线程共用一个文件描述符表和内存指针。
4、线程安全问题
对于线程安全问题先举个例子
一个房间的桌子上放着100只烧鸡把小明同学叫来让他把这100只烧鸡全部吃完(小明相当于一个线程)但是一个人吃100只鸡显然效率很低。于是再把小刚同学叫来(再创建一个线程)让小刚和小明共同把这100只鸡吃完。此时两个人吃100只鸡显然比一个人吃100只鸡的效率要高的多。如果再叫来两三个其他同学这时的效率就会更高。但是如果一直再叫来其他同学比如叫到了50名同学50名同学共同吃这100只鸡其中两人都想吃同一只鸡这两人间就会发生冲突(即线程安全问题)甚至冲突过大会把桌子掀翻这时所有的人都吃不了鸡了(直接带走进程所有线程无法继续工作)。
综上总结如下
虽然多线程的方式能够提高工作效率但是也并非“线性增长”当一个进程中的线程过多时线程与线程间就会出现互相影响的情况会拖慢效率甚至会抛出异常使整个进程终止(如果及时捕捉到异常也是不会终止的)。线程数目如果太多线程的调度开销也会非常明显会因为调度开销拖慢程序性能。
5、创建线程
线程是操作系统提供的概念同时操作系统也提供了一些线程相关的api供程序员使用。
操作系统提供的原生api是C语言写的并且不同操作系统所提供的线程api是不同的是不是我们Java程序猿就得去学习C语言呢
并不是的Java对操作系统提供的线程api统一进行了封装在标准库中提供了Thread类我们可以通过Thread类来创建和使用多线程。
而创建线程的方式有两种
继承Thread重写run实现Runnable重写run
5.1 继承Thread类重写run
5.1.1 创建Thread类对象
Thread类被封装在了java.lang包中java.lang是Java的核心包包含了String、Math、System、Thread、Runnable等等这个包中的类被自动导入到每个Java程序中无需显式导入。所以当我们使用Thread类时不会自动显示导入包。 5.1.2 重写run方法
作为程序员我们需要创建一个类继承于Thread并且重写其中的run方法在run这个方法中我们可以根据自己的思维将这个线程要做的任务写在这个run方法中。 这个run方法就相当于线程的入口。
为后续观察多线程的状态这里使用死循环的方式打印“hello thread”再使用Thread中静态的sleep方法休眠1秒(防止CPU红温)。
使用sleep方法会抛出受查异常解决方法有两个
throws进行异常声明try-catch进行异常捕获
但是由于run为重写方法不能使用throws在函数头声明只能使用try-catch捕获。
5.1.3 start方法创建线程
start方法的作用是真正创建一个新的进程相当于多了一个执行流多了一个干活的人让代码能够“一心两用”同时做两件事。
在main方法(主线程)中使用Thread对象调用start方法创建线程并且在main方法中循环打印“hello main”观察多线程现象。 注意start的作用才是创建线程run方法只是线程的入口不是创建线程。 如果按照我们之前学习的程序运行逻辑程序遇到死循环就会一直停留在那里(单线程模式)但是我们现在创建了多个线程会发生什么样的情况呢
多线程运行 运行后“hello main”和“hello thread”无规律交替打印这就是多线程。
class MyThread extends Thread{Overridepublic void run() {//线程入口while (true) {System.out.println(hello thread);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread thread new MyThread();//start - 真正的创建线程thread.start();while (true) {System.out.println(hello main);Thread.sleep(1000);}}
}
5.1.4 抢占式执行 观察到“hello main”和“hello thread”的打印是随机的也就是这两个线程的调度是随机的谁先执行谁后执行都是无法预测的我们称这种情况为“抢占式执行”通俗来说就是谁先抢到谁就先执行。
我们唯一能做的就是给线程设置优先级但是对于操作系统来说也只是仅供参考不会一定的按照优先级的顺序来调度执行。
5.2 实现Runnable重写run【解耦合】★★★
我们可以把要重写的run方法抽象出来使用自定义类实现Runnable接口在类中重写run方法(即要完成的任务)将要完成的任务和线程分离开来实现与线程Thread的解耦合。 就是仅仅把runnable当做一个任务单纯的把任务抽象到runnable接口的run方法中最后线程还是要靠Thread来创建。
这样解耦合的有以下优点
将所要完成的任务和线程分类开来而不是把任务直接写到线程当中以后可以通过其他方式执行该任务(不一定是在线程中)使线程是线程任务是任务。方便以后修改任务时不会影响到线程方便代码的维护(容易改不会一改一大片)
class MyRunnable implements Runnable {Overridepublic void run() {//run -- 相当于线程的入口while (true) {System.out.println(hello thread);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class Demo2 {public static void main(String[] args) throws InterruptedException {//任务Runnable runnable new MyRunnable();//线程Thread thread new Thread(runnable);//start -- 真正的创建线程thread.start();while (true) {System.out.println(hello main);Thread.sleep(1000);}}
} 6、知识拓展
6.1 拓展一名词解释——api
上文很多地方都提到了api但是大家都知道啥是api嘛
apiapplication programming interface应用程序编程接口。
通俗来说api就是别人写的一些函数/类你直接拿过来就能用。
api是一个广义的概念操作系统会提供api、标准库会提供api、第三方库会提供api、其他各种开源项目会提供api、甚至工作中项目组给你的代码中也会提供api。
api也可以理解为别人给你提供的库/程序你都能用来干啥。
举个例子对于同班同学你可以给他在微信上发消息、可以问他题、可以和他聊天、....这是你同学向你提供的api你谈了个对象你可以和你的对象亲亲抱抱举高高....这是你对象向你提供的api。
而基于api你可以用来编程api的目的就是用于编程。
比如接上例基于你同学或者对象向你提供的api你可以做出规划(编程)周末约同学打球周末约对象看电影......
而对于Java程序猿的我们我们可以使用标准库向我们提供的api去编程比如ArrayList、StringBuffer、....... 在计算机界Demo/Sample/quick start 的意思是示例、演示的意思告诉我们如何使用。 而test是更为详细的测试过程。 6.2 拓展二异常处理方式
在上文中我们提到对于受查异常有两种处理方式
throwstry-catch
当我们使用IDEA进行自动的异常处理时它是这样处理的 它在catch中又重新拋了一个新的异常只不过拋了个非受查的异常所以没有再编译报错了这种方法仅仅是满足了语法的要求但是对于异常来说就相当于没处理异常。在实际开发中我们并不会这么干~
在实际工作中通常会这样处理异常
记录异常信息作为日志后续根据日志调查问题。——使程序仍然正常执行不会因为这个异常就终止。不交给jvm处理服务器是7*24小时运行的如果服务器因为异常导致崩溃就无法给客户提供服务这对于服务器来说非常关键进行重试。有的异常是概率性发生的如网络抖动原因报警机制——如果是特别严重的问题程序会立即通知程序猿处理通过写代码来以短信、电话、微信等方式通知程序猿。
6.3 拓展三名词解释——客户端服务器
客户端(client)服务器(server)指的两个程序(两个软件)这两个程序通过配合完成一些工作。
客户端向服务器发送的数据称为“请求”(request)。
服务器向客户端返回的数据称为“响应”(response)。
客服端和服务器的主要区别如下
主动发起请求的一方叫做客户端。被动接受请求返回响应的一方叫做服务器。通常一个服务器给多个客户端提供服务。服务器不知道客户端来不来啥时候来所以只能将程序一直持续的运行下去即7*24小时的跑(007)。(正因此异常导致服务器崩溃的后果是非常严重的必须将异常处理好) 6.4 拓展四高内聚低耦合
6.4.1 耦合
耦合指两个东西的关联程度。关联度越高耦合就越大关联度越低耦合就越小。
在代码中我们希望代码间是低耦合的(解耦)因为在开发中代码是经常会修改的低耦合的代码可维护性高(也就是好改)要修改代码的话改一小部分就行能够防止“改一个改坏一片”的情况发生。
举个例子
你结婚后你媳妇生病住院了你只能立刻放下手中的活到医院来照顾她、陪伴她什么工作也干不了。因为你媳妇对你来说是很主要的人你媳妇的生病对你的工作/生活影响很大你必须放下你手头的事哪怕再紧急的工作也得放下。
这就说明你和你媳妇是高耦合你媳妇出现了状况对你的影响很大你啥事也干不了。
而如果你高中时的白月光发了个朋友圈说她生病住院了对你来说呢你只是点了个赞评论了句“早日康复”接着放下手机回头就忘了这件事对你一点影响也没有。
这就说明你和你高中的白月光是低耦合她出现了啥状况对你一定影响也没有。
6.4.2 内聚
内聚是指有相同的功能、逻辑关系的东西的集中程度。
代码中我们希望高内聚将相同逻辑、功能的或者有关联的代码放到一起
而不是这放一块那放一块的低内聚。
举个例子
你结婚有了孩子后你媳妇这个人她比较懒总是把衣服这扔一件那扔一件的有的衣服在沙发有的衣服在床上有的衣服在椅子上有的还在沙发缝里。有一天你媳妇让你给孩子拿一件衣服由于衣服哪都有你非常的痛苦遍历了整个屋子都没找到孩子的衣服在哪。
这就反应的是低内聚。
后来你媳妇变得贤惠了把衣服都知道收拾整理好放到衣柜了你再给孩子找衣服的时候直接去衣柜里拿就行了。
这反应的就是高内聚。
综上高内聚(一个模块内有关联的东西放在一块)低耦合(模块之间依赖尽量小影响尽量小)。 END