3年开发经验的程序员不会多线程!网友:多线程入门都总结这里了
yuyutoo 2024-10-12 01:03 5 浏览 0 评论
分享阿里 P8 高级架构师吐血总结的 《Java 核心知识体系&面试资料.pdf》
据说是阿里 P8 级高级架构师吐血总结的一份 Java 核心知识.pdf, 内容覆盖很广,Java 核心基础、Java 多线程、高并发、Spring、微服务、Netty 与 RPC、Zookeeper、Kafka、RabbitMQ、Habase、设计模式、负载均衡、分布式缓存、Hadoop、Spark、Storm、云计算等。
另外,附送 100G 学习、面试视频文档哟~
获取方式:【关注 + 转发】后,私信我,回复关键字【资源】,即可免费无套路获取哦~
以下是资源的部分目录以及内容截图:
重要的事再说一遍,获取方式:【关注 + 转发】后,私信我,回复关键字【资源】,即可免费无套路获取哦~
正文开始
思维导图:
一 进程和多线程简介
1.1 相关概念
何为线程?
线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
何为进程?
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。
线程和进程有何不同?
线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。
1.2 多线程
何为多线程?
多线程就是几乎同时执行多个线程(一个处理器在某一个时间点上永远都只能是一个线程!即使这个处理器是多核的,除非有多个处理器才能实现多个线程同时运行。)。几乎同时是因为实际上多线程程序中的多个线程实际上是一个线程执行一会然后其他的线程再执行,并不是很多书籍所谓的同时执行。
为什么多线程是必要的?
- 使用线程可以把占据长时间的程序中的任务放到后台去处理
- 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
- 程序的运行速度可能加快
二 使用多线程
2.1继承Thread类
MyThread.java
public class MyThread extends Thread { @Override public void run() { super.run(); System.out.println("MyThread"); } } 复制代码
Run.java
public class Run { public static void main(String[] args) { MyThread mythread = new MyThread(); mythread.start(); System.out.println("运行结束"); } } 复制代码
运行结果:
从上面的运行结果可以看出:线程是一个子任务,CPU以不确定的方式,或者说是以随机的时间来调用线程中的run方法。2.2实现Runnable接口
推荐实现Runnable接口方式开发多线程,因为Java单继承但是可以实现多个接口。
MyRunnable.java
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("MyRunnable"); } } 复制代码
Run.java
public class Run { public static void main(String[] args) { Runnable runnable=new MyRunnable(); Thread thread=new Thread(runnable); thread.start(); System.out.println("运行结束!"); } } 复制代码
运行结果:
三 实例变量和线程安全
定义线程类中的实例变量针对其他线程可以有共享和不共享之分
3.1 不共享数据的情况
MyThread.java
public class MyThread extends Thread { private int count = 5; public MyThread(String name) { super(); this.setName(name); } @Override public void run() { super.run(); while (count > 0) { count--; System.out.println("由 " + MyThread.currentThread().getName() + " 计算,count=" + count); } } } 复制代码
Run.java
public class Run { public static void main(String[] args) { MyThread a = new MyThread("A"); MyThread b = new MyThread("B"); MyThread c = new MyThread("C"); a.start(); b.start(); c.start(); } } 复制代码
运行结果:
可以看出每个线程都有一个属于自己的实例变量count,它们之间互不影响。我们再来看看另一种情况。3.2 共享数据的情况
MyThread.java
public class MyThread extends Thread { private int count = 5; @Override public void run() { super.run(); count--; System.out.println("由 " + MyThread.currentThread().getName() + " 计算,count=" + count); } } 复制代码
Run.java
public class Run { public static void main(String[] args) { MyThread mythread=new MyThread(); //下列线程都是通过mythread对象创建的 Thread a=new Thread(mythread,"A"); Thread b=new Thread(mythread,"B"); Thread c=new Thread(mythread,"C"); Thread d=new Thread(mythread,"D"); Thread e=new Thread(mythread,"E"); a.start(); b.start(); c.start(); d.start(); e.start(); } } 复制代码
运行结果:
可以看出这里已经出现了错误,我们想要的是依次递减的结果。为什么呢??因为在大多数jvm中,count--的操作分为如下下三步:
- 取得原有count值
- 计算i -1
- 对i进行赋值
所以多个线程同时访问时出现问题就是难以避免的了。
那么有没有什么解决办法呢?
答案是:当然有,而且很简单。
在run方法前加上synchronized关键字即可得到正确答案。
加上关键字后的运行结果:
四 一些常用方法
4.1 currentThread()
返回对当前正在执行的线程对象的引用。
4.2 getId()
返回此线程的标识符
4.3 getName()
返回此线程的名称
4.4 getPriority()
返回此线程的优先级
4.5 isAlive()
测试这个线程是否还处于活动状态。
什么是活动状态呢?
活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备运行的状态。
4.6 sleep(long millis)
使当前正在执行的线程以指定的毫秒数“休眠”(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
4.7 interrupt()
中断这个线程。
4.8 interrupted() 和isInterrupted()
interrupted():测试当前线程是否已经是中断状态,执行后具有将状态标志清除为false的功能
isInterrupted(): 测试线程Thread对相关是否已经是中断状态,但部清楚状态标志
4.9 setName(String name)
将此线程的名称更改为等于参数 name 。
4.10 isDaemon()
测试这个线程是否是守护线程。
4.11 setDaemon(boolean on)
将此线程标记为 daemon线程或用户线程。
4.12 join()
在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。
join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行
4.13 yield()
yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU时间。注意:放弃的时间不确定,可能一会就会重新获得CPU时间片。
4.14 setPriority(int newPriority)
更改此线程的优先级
五 如何停止一个线程呢?
stop(),suspend(),resume()(仅用于与suspend()一起使用)这些方法已被弃用,所以我这里不予讲解。
5.1 使用interrupt()方法
我们上面提到了interrupt()方法,先来试一下interrupt()方法能不能停止线程 MyThread.java
public class MyThread extends Thread { @Override public void run() { super.run(); for (int i = 0; i < 5000000; i++) { System.out.println("i=" + (i + 1)); } } } 复制代码
Run.java
public class Run { public static void main(String[] args) { try { MyThread thread = new MyThread(); thread.start(); Thread.sleep(2000); thread.interrupt(); } catch (InterruptedException e) { System.out.println("main catch"); e.printStackTrace(); } } } 复制代码
运行上诉代码你会发现,线程并不会终止。
针对上面代码的一个改进:
interrupted()方法判断线程是否停止,如果是停止状态则break
MyThread.java
public class MyThread extends Thread { @Override public void run() { super.run(); for (int i = 0; i < 500000; i++) { if (this.interrupted()) { System.out.println("已经是停止状态了!我要退出了!"); break; } System.out.println("i=" + (i + 1)); } System.out.println("看到这句话说明线程并未终止------"); } } 复制代码
Run.java
public class Run { public static void main(String[] args) { try { MyThread thread = new MyThread(); thread.start(); Thread.sleep(2000); thread.interrupt(); } catch (InterruptedException e) { System.out.println("main catch"); e.printStackTrace(); } System.out.println("end!"); } } 复制代码
运行结果:
for循环虽然停止执行了,但是for循环下面的语句还是会执行,说明线程并未被停止。5.2 使用return停止线程
MyThread.java
public class MyThread extends Thread { @Override public void run() { while (true) { if (this.isInterrupted()) { System.out.println("??停止了!"); return; } System.out.println("timer=" + System.currentTimeMillis()); } } } 复制代码
Run.java
public class Run { public static void main(String[] args) throws InterruptedException { MyThread t=new MyThread(); t.start(); Thread.sleep(2000); t.interrupt(); } } 复制代码
运行结果:
当然还有其他停止线程的方法,后面再做介绍。六 线程的优先级
每个线程都具有各自的优先级,线程的优先级可以在程序中表明该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这个并不意味着低 优先级的线程得不到运行,而只是它运行的几率比较小,如垃圾回收机制线程的优先级就比较低。所以很多垃圾得不到及时的回收处理。
线程优先级具有继承特性比如A线程启动B线程,则B线程的优先级和A是一样的。
线程优先级具有随机性也就是说线程优先级高的不一定每一次都先执行完。
Thread类中包含的成员变量代表了线程的某些优先级。如Thread.MIN_PRIORITY(常数1),Thread.NORM_PRIORITY(常数5), Thread.MAX_PRIORITY(常数10)。其中每个线程的优先级都在Thread.MIN_PRIORITY(常数1) 到Thread.MAX_PRIORITY(常数10) 之间,在默认情况下优先级都是Thread.NORM_PRIORITY(常数5)。
学过操作系统这门课程的话,我们可以发现多线程优先级或多或少借鉴了操作系统对进程的管理。
线程优先级具有继承特性测试代码:
MyThread1.java:
public class MyThread1 extends Thread { @Override public void run() { System.out.println("MyThread1 run priority=" + this.getPriority()); MyThread2 thread2 = new MyThread2(); thread2.start(); } } 复制代码
MyThread2.java:
public class MyThread2 extends Thread { @Override public void run() { System.out.println("MyThread2 run priority=" + this.getPriority()); } } 复制代码
Run.java:
public class Run { public static void main(String[] args) { System.out.println("main thread begin priority=" + Thread.currentThread().getPriority()); Thread.currentThread().setPriority(6); System.out.println("main thread end priority=" + Thread.currentThread().getPriority()); MyThread1 thread1 = new MyThread1(); thread1.start(); } } 复制代码
运行结果:
七 Java多线程分类
7.1 多线程分类
用户线程:运行在前台,执行具体的任务,如程序的主线程、连接网络的子线程等都是用户线程
守护线程:运行在后台,为其他前台线程服务.也可以说守护线程是JVM中非守护线程的 “佣人”。
特点:一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作
应用:数据库连接池中的检测线程,JVM虚拟机启动后的检测线程
最常见的守护线程:垃圾回收线程
7.2 如何设置守护线程?
可以通过调用Thead类的setDaemon(true)方法设置当前的线程为守护线程
注意事项:
1. setDaemon(true)必须在start()方法前执行,否则会抛出IllegalThreadStateException异常 2. 在守护线程中产生的新线程也是守护线程 3. 不是所有的任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑 复制代码
MyThread.java:
public class MyThread extends Thread { private int i = 0; @Override public void run() { try { while (true) { i++; System.out.println("i=" + (i)); Thread.sleep(100); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 复制代码
Run.java:
public class Run { public static void main(String[] args) { try { MyThread thread = new MyThread(); thread.setDaemon(true); thread.start(); Thread.sleep(5000); System.out.println("我离开thread对象也不再打印了,也就是停止了!"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 复制代码
运行结果:
作者:SnailClimb
相关推荐
- Mysql和Oracle实现序列自增(oracle创建序列的sql)
-
Mysql和Oracle实现序列自增/*ORACLE设置自增序列oracle本身不支持如mysql的AUTO_INCREMENT自增方式,我们可以用序列加触发器的形式实现,假如有一个表T_WORKM...
- 关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)
-
概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...
- MySQL CREATE TABLE 简单设计模板交流
-
推荐用MySQL8.0(2018/4/19发布,开发者说同比5.7快2倍)或同类型以上版本....
- mysql学习9:创建数据库(mysql5.5创建数据库)
-
前言:我也是在学习过程中,不对的地方请谅解showdatabases;#查看数据库表createdatabasename...
- MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别
-
执行"CREATETABLE新表ASSELECT*FROM原表;"后,新表与原表的字段一致,但主键、索引不会复制到新表,会把原表的表记录复制到新表。...
- Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出
-
在街上看到的PandaDunk的超载可能让一些球鞋迷们望而却步,但Dunk的浪潮仍然强劲,看不到尽头。我们看到的很多版本都是为女性和儿童制作的,这种新配色为后者引入了一种令人耳目一新的新选择,而...
- 美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍
-
多功能雷达AN/SPY-1的特性和技术能力,该雷达已经在美国海军服役了30多年,其修改-AN/SPY-1A、AN/SPY-1B(V)、AN/SPY-1D、AN/SPY-1D(V),以及雷神...
- 汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)
-
全面分析汽车音响使用或安装技术常识一:主机是大多数人最熟习的音响器材,有关主机的各种性能及规格,也是耳熟能详的事,以下是一些在使用或安装时,比较需要注意的事项:LOUDNESS:几年前的主机,此按...
- 【推荐】ProAc Response系列扬声器逐个看
-
有考牌(公认好声音)扬声器之称ProAcTablette小音箱,相信不少音响发烧友都曾经,或者现在依然持有,正当大家逐渐掌握Tablette的摆位设定与器材配搭之后,下一步就会考虑升级至表现更全...
- #本站首晒# 漂洋过海来看你 — BLACK&DECKER 百得 BDH2000L无绳吸尘器 开箱
-
作者:初吻给了烟sco混迹张大妈时日不短了,手没少剁。家里有了汪星人,吸尘器使用频率相当高,偶尔零星打扫用卧式的实在麻烦(汪星人:你这分明是找借口,我掉毛是满屋子都有,铲屎君都是用卧式满屋子吸的,你...
- 专题|一个品牌一件产品(英国篇)之Quested(罗杰之声)
-
Quested(罗杰之声)代表产品:Q212FS品牌介绍Quested(罗杰之声)是录音监听领域的传奇品牌,由英国录音师RogerQuested于1985年创立。在成立Quested之前,Roger...
- 常用半导体中英对照表(建议收藏)(半导体英文术语)
-
作为一个源自国外的技术,半导体产业涉及许多英文术语。加之从业者很多都有海外经历或习惯于用英文表达相关技术和工艺节点,这就导致许多英文术语翻译成中文后,仍有不少人照应不上或不知如何翻译。为此,我们整理了...
- Fyne Audio F502SP 2.5音路低音反射式落地音箱评测
-
FyneAudio的F500系列,有新成员了!不过,新成员不是新的款式,却是根据原有款式提出特别版。特别版产品在原有型号后标注了SP字样,意思是SpecialProduction。Fyne一共推出...
- 有哪些免费的内存数据库(In-Memory Database)
-
以下是一些常见的免费的内存数据库:1.Redis:Redis是一个开源的内存数据库,它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。Redis提供了快速的读写操作,并且支持持久化数据到磁...
- RazorSQL Mac版(SQL数据库查询工具)
-
RazorSQLMac特别版是一款看似简单实则功能非常出色的SQL数据库查询、编辑、浏览和管理工具。RazorSQLformac特别版可以帮你管理多个数据库,支持主流的30多种数据库,包括Ca...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
推荐7个模板代码和其他游戏源码下载的网址
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
-
- Mysql和Oracle实现序列自增(oracle创建序列的sql)
- 关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)
- MySQL CREATE TABLE 简单设计模板交流
- mysql学习9:创建数据库(mysql5.5创建数据库)
- MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别
- Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出
- 美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍
- 汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)
- 【推荐】ProAc Response系列扬声器逐个看
- #本站首晒# 漂洋过海来看你 — BLACK&DECKER 百得 BDH2000L无绳吸尘器 开箱
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)