第十二章 多线程基础
文章目录
- 12.1 进程与线程
- 12.2 创建线程
- 12.2.1 继承Thread类
- 12.2.2 实现Runnable接口
- 12.2.3 区别和联系
- 12.3 终止线程
- 12.4 线程常用方法
- 12.4.1 注意事项
- 12.5 用户线程和守护线程
- 12.6 线程的生命周期
- 12.7 线程的同步
- 12.7.1 Synchronized
- 12.7.1 互斥锁
- 12.7.2 死锁
- 12.7.3 释放锁
- 12.8 本章作业
12.1 进程与线程
- 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。
- 线程: 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
- 单线程:同一时刻,只允许执行一个线程。
- 多线程:同一时刻,可以执行多个线程。
12.2 创建线程
12.2.1 继承Thread类
继承Thread类,重写run方法。
class Cat extends Thread {int times = 0;@Overridepublic void run() {while (true) {System.out.println("这是一只猫咪" + (++times) + " 线程名=" + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}if (times == 20) {break;}}} } //使用方式 new Cat().start();
12.2.2 实现Runnable接口
实现Runnable接口,重写run方法。
class Dog implements Runnable {int count = 0;@Overridepublic void run() {while (true) {System.out.println("小狗" + (++count) + " 线程名=" + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}if (count == 10) {break;}}} } /*使用方式 Dog dog = new Dog(); Thread thread = new Thread(dog); thread.start(); */
// Dog类并未拥有真正执行多线程的start方法,因此需要借助Thread类,下述代码 模拟 这种 代理模式 public class ThreadProxySimulation {public static void main(String[] args) {Tiger tiger = new Tiger();ThreadProxy threadProxy = new ThreadProxy(tiger);threadProxy.star(); //暴风新云裂} }class Tiger implements Runnable {@Overridepublic void run() {System.out.println("暴风新云裂");} }class ThreadProxy implements Runnable {private Runnable target = null;public ThreadProxy(Runnable target) {this.target = target;}@Overridepublic void run() {if (target != null) {target.run();}}public void star() {star0();}public void star0() {run();}}
12.2.3 区别和联系
继承Thread类和实现Runnable的区别和联系。
- 从Java的设计来看,二者本质上没有区别,Thread类本身实现了Runnable接口。
- 实现Runnable接口方式更加适合多个线程共享一个资源的情况,而且避免了单继承的限制,建议使用Runnable。
12.3 终止线程
当进程完成任务后,会自动退出。
还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式。
// 在其他线程中,可以通过更改loop来更改线程T的状态 class T extends Thread {private int count = 0;private boolean loop = true;public void setLoop(boolean loop) {this.loop = loop;}@Overridepublic void run() {while (loop) {System.out.println("T 运行中" + (++count));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} }
12.4 线程常用方法
代码示例如下:
public class ThreadMethod01 {public static void main(String[] args) {Dog dog = new Dog();dog.start();Cat cat = new Cat();Thread thread = new Thread(cat);thread.setName("猫猫队");thread.setPriority(Thread.MAX_PRIORITY);thread.start();} }class Dog extends Thread { //自定义的线程类@Overridepublic void run() {this.setName("汪汪队");System.out.println("Dog类的线程名为:" + this.getName());this.setPriority(Thread.MIN_PRIORITY);System.out.println("Dog类的优先级为:" + this.getPriority());} }class Cat implements Runnable {@Overridepublic void run() {System.out.println("Cat类的线程名为:" + Thread.currentThread().getName());System.out.println("Cat类的优先级为:" + Thread.currentThread().getPriority());} } /*Dog类的线程名为:汪汪队 Dog类的优先级为:1 Cat类的线程名为:猫猫队 Cat类的优先级为:10*/
12.4.1 注意事项
- start底层会创建新的线程,调用run方法。如果只是调用run方法,不会创建新的线程。
- 线程优先级的范围为[1,10],其中Thread.MIN_PRIORITY = 1、Thread.MAX_PRIORITY = 10、,默认情况下,每一个线程都会分配一个优先级 Thread.NORM_PRIORITY =5。
- interrupt方法用于中断线程,但并没有真正的结束线程,所以一般用于中断正在休眠的进程。
12.5 用户线程和守护线程
用户线程:也叫做工作线程,当线程的任务执行完成或通知方式结束。
守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束。
常见的守护线程:垃圾回收机制。
示例代码如下:当主线程输出5次后,主线程结束,守护线程自动结束。
public class DaemonThread {public static void main(String[] args) throws InterruptedException {James james = new James();james.setDaemon(true);james.start();for (int i = 0; i < 5; i++) {System.out.println("欧文正在练运球");Thread.sleep(1000);}} }class James extends Thread {@Overridepublic void run() {while (true) {System.out.println("James正在守护克利夫兰");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} }
12.6 线程的生命周期
JDK中用Thread.State枚举表示了线程的几种状态
线程的状态转换图
12.7 线程的同步
- 在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就需要使用同步访问技术,保证数据在任何同一时刻,最多只有一个线程访问,以保证数据的完整性。
- 线程同步:即当有一个线程对内存进行操作时,其他线程都不可以对这个内存进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作。
12.7.1 Synchronized
同步代码块:
synchronized (对象) { //得到对象的锁,才能操作同步代码// 需要同步的代码块 }
public class SellTicketTwoTest {public static void main(String[] args) {SellTicketTwo sellTicketTwo = new SellTicketTwo();new Thread(sellTicketTwo).start();new Thread(sellTicketTwo).start();new Thread(sellTicketTwo).start();} }class SellTicketTwo implements Runnable {private static int ticketNum = 100;private boolean loop = true;Object object = new Object();@Overridepublic void run() {while (loop) {sell();}}public void sell() {synchronized (this) {if (ticketNum <= 0) {System.out.println("售票结束...");loop = false;return;}System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"+ " 剩余票数=" + (--ticketNum));try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}} }
同步方法:
public synchronized void m(String name) {// 需要同步的代码块 }
public class SellTicketOneTest {public static void main(String[] args) {SellTicketOne sellTicketOne = new SellTicketOne();new Thread(sellTicketOne).start();new Thread(sellTicketOne).start();new Thread(sellTicketOne).start();} }class SellTicketOne implements Runnable {private static int ticketNum = 100;private boolean loop = true;@Overridepublic void run() {while (loop) {sell();}}public synchronized void sell() {if (ticketNum <= 0) {System.out.println("售票结束...");loop = false;return;}System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"+ " 剩余票数=" + (--ticketNum));try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}} }
12.7.1 互斥锁
定义:Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
每个对象都对应一个可称为 “互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
关键字synchronized用来与对象的互斥锁联系,当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。
同步的局限性:导致程序的执行效率降低。
同步方法(非静态)的锁可以是this,也可以是其他对象(要求是同一个对象),默认锁的对象为this。
public void sell() {synchronized(this || 其他单一对象) {// 需要同步的代码块} }
同步方法(静态的)的锁只能为当前类本身,默认锁的对象为当前类.class。
public static void sell() {synchronized(className.class) {// 需要同步的代码块} }
实现的落地步骤:
- 分析上锁的代码。
- 选项同步代码块或同步方法。
- 要求多个线程的锁对象为同一个。
12.7.2 死锁
- 定义:如果某一组进程中的每一个进程都在等待仅有该组进程的其他进程才能引发事件的发生,那么该组进程是死锁。在编程中一定要避免死锁的发生。
12.7.3 释放锁
如下操作会释放锁。
如下操作不会释放锁。
12.8 本章作业
-
public class Homework01 {public static void main(String[] args) {A a = new A();B b = new B(a);a.start();b.start();} }class A extends Thread {private boolean loop = true;public void setLoop(boolean loop) {this.loop = loop;}@Overridepublic void run() {while (loop) {System.out.println((int) (100 * Math.random() + 1));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("a线程退出...");} }class B extends Thread {private A a;public B(A a) {this.a = a;}Scanner scanner = new Scanner(System.in);@Overridepublic void run() {while (true) {System.out.println("请输入你指令(Q)表示退出:");char key = scanner.next().toUpperCase().charAt(0);if (key == 'Q') {a.setLoop(false); //以通知的方式结束a线程System.out.println("b线程退出.");break;}}} }
-
public class Homework02 {public static void main(String[] args) {WithdrawMoney withdrawMoney = new WithdrawMoney();Thread thread1 = new Thread(withdrawMoney);Thread thread2 = new Thread(withdrawMoney);thread1.start();thread2.start();} }class WithdrawMoney implements Runnable {private int money = 10000;private boolean loop = true;@Overridepublic void run() {while (loop) {withdraw();}}public void withdraw() {synchronized (this) {if (money < 1000) {System.out.println(Thread.currentThread().getName() + "余额小于1000,不能取钱");loop = false;} else {money -= 1000;System.out.println(Thread.currentThread().getName() + "取出了1000 当前余额=" + money);}}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}} }
第十二章 多线程基础相关推荐
- 第三十二章 XML基础知识概念
文章目录 第三十二章 XML基础知识概念 attribute CDATA区域 comment content model default namespace DOM DTD(文档类型定义) eleme ...
- 《Kotlin 程序设计》第十二章 Kotlin的多线程:协程(Coroutines)
第十二章 Kotlin的多线程:协程(Coroutines) Kotlin 1.1 introduced coroutines, a new way of writing asynchronous, ...
- iPhone开发基础教程笔记(十二)--第十二章 使用Quartz和OpenGL绘图
第十二章 使用Quartz和OpenGL绘图 有时应用程序需要能够自定义绘图.一个库是Quartz 2D,她是Core Graphics框架的一部分:另一个库是OpenGL ES,她是跨平台的图形库. ...
- css层叠样式表基础学习笔记--第十二章 我要自学网首页实战
第十二章 我要自学网首页实战 12-01 页面分析 12-02 工作准备 12-03 搜索区块页面结构 12-04 导航条布局 12-05 幻灯片布局 12-06 公告栏布局 12-07 远程培训班布 ...
- 【Linux命令】《鸟哥Linux基础》第十二章 学习shell脚本
第十二章 学习shell脚本 通常利用shell脚本完成服务器的检测工作,不涉及大量运算. 12.1 简单shell脚本介绍 12.2 简单shell脚本练习 12.2.1 简单范例 范例1:永远的开 ...
- 系统架构师学习笔记_第十二章_连载
第十二章 系统安全架构设计 12.1 信息系统安全架构的简单描述 信息安全的特征 是为了保证信息的 机密性.完整性.可用性.可控性.不可抵赖性. 以风险策略为基础. 12.1.1 信息安全的现状 ...
- 鸟哥的Linux私房菜(服务器)- 第十二章、网络参数控管者: DHCP 服务器
第十二章.网络参数控管者: DHCP 服务器 最近更新日期:2011/07/27 想象两种情况:(1)如果你在工作单位使用的是笔记本电脑,而且常常要带着你的笔记本电脑到处跑, 那么由第四章.连上 In ...
- matlab气相分解反应动力学,第十二章 化学动力学.ppt
快反应 慢反应 速控法 稳态法 (1) 一级反应 (2) 二级反应 高压时 低压时 RRKM理论 §12.7 光化学反应 * 物理化学(下) PHYSICAL CHEMISTRY (11) 碰撞理论 ...
- 《Reids 设计与实现》第十二章 复制
<Reids 设计与实现>第十二章 复制 文章目录 <Reids 设计与实现>第十二章 复制 一.简介 二.旧版复制功能的实现 1.同步 2.命令传播 三.旧版复制功能的缺陷 ...
最新文章
- vb跨域访问ajax,解决AJAX的跨域访问-两种有效示例
- php人民币转换,PHP字符串转换RMB形式数字
- TCP/IP学习笔记(一)分层模型概述
- linux AB测试
- eclipse中使用git回到之前的版本
- mssql数据库简繁体互转
- 腾讯企业邮箱好还是阿里云企业邮箱好?
- 读书狂想之《平凡的世界》不平凡的人生
- Java随笔记 - 内核缓冲区与进程缓冲区
- 产品周报第27期|会员新增拉黑用户权益;CSDN APP V5.1.0版本发布……
- 如何画出漂亮的神经网络图?
- 大连交通大学IPTV使用方法
- python skimage 填补图像孔洞
- 人脸识别眨眼张嘴软件_人脸识别张张嘴眨眨眼jar、css、js
- 我想成为一只IT小小鸟
- css3 烟 蚊香_前端每日实战:48# 视频演示如何用纯 CSS 创作一盘传统蚊香
- 【报告分享】AIoT智能生活场景营销研究报告-小米中传(附下载)
- 免费ARP(gratuitous ARP)
- 西门子博途TIA PORTAL不同版本上传和下载时要注意的问题
- Dijkstra 算法-《数据结构》严蔚敏