Java(九)(多线程,线程安全,实现线程的方法,线程同步,线程池,并发和并行,线程的六种状态)

目录

多线程

线程

实现线程的方法

方法一:继承Thread父类

方法二:实现Runnable接口

方法三:Callable接口和FutureTask类来实现

Thread方法

线程安全

线程同步

同步代码块

同步方法

Lock锁

线程池

线程池对象的创建方式一:

线程池处理Runnable任务

线程池处理Callable任务

并发和并行

并发的含义

并行的理解

线程的六种状态


多线程

线程

线程(Thread是一个程序内部单独一条执行流程),程序中如果只有一条执行流程,那这个程序就是单线程的程序

实现线程的方法

方法一:继承Thread父类

我们先写一个MyThread类,表示我们创建的子线程类

public class MyThread extends Thread{@Overridepublic void run(){for (int i = 0; i <= 5; i++) {System.out.println("子线程MyThread输出"+i);}}
}

我们实现main方法

public class main_Thread {public static void main(String[] args) {Thread t = new MyThread();t.start();for (int i = 0; i <= 5; i++) {System.out.println("主线程main输出:"+i);}}
}

输出结果为

说明我们现在有两个线程,每一个线程都先运行

需要我们注意的是:

第一点: 我们在子类中重写了run方法,但是我们在调用创建的线程对象t的方法是start(),如果是run()方法会变成单线程,会先执行完run方法里的才会执行main函数中的

第二点: 我们的子线程要放到主线程的前面

缺点:一个子类只能继承一个父类,不能再继承其他类,所以继承了Thread之后,不能继承其他类,会导致功能减少

方法二:实现Runnable接口

(1)定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法

public class MyRunnable implements Runnable{@Overridepublic void run(){for (int i = 0; i < 5; i++) {System.out.println("子线程1---->"+i);}}
}

(2)创建MyRunnable任务对象

Runnable r = new MyRunnable();

(3)把MyRunnable任务对象交给Thread处理并且调用对象的start()方法启动线程

new Thread(r).start();

下面是mian方法的完整代码

public class main_Thread {public static void main(String[] args) {// 创建MyRunnable任务对象Runnable r = new MyRunnable();new Thread(r).start();for (int i = 0; i < 5; i++) {System.out.println("mian线程--->"+i);}}
}

代码优化

不创建子类,用匿名内部类

public class main_Thread {public static void main(String[] args) {// 创建MyRunnable任务对象new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程--->"+i);}}}).start();for (int i = 0; i < 5; i++) {System.out.println("mian线程--->"+i);}}
}

优点: 任务类只能实现接口,可以继续继承其他类,实现其他接口

缺点: 需要多一个Runable对象

方法三:Callable接口和FutureTask类来实现

使用原因:因为我们上面两个方法都是调用start方法,进而让调用run方法的,而run方法是void类型的,不会给我们返回值,这时候就要用到方法三

最大优点:可以返回线程执行完毕后的结果

创建线程的步骤:

1.创建任务对象:

(1)定义一个类实现Callable接口,重写call方法,封装要做的事情,和返回的数据

import java.util.concurrent.Callable;public class MyCall implements Callable<String> {private int n ;public MyCall(int n) {this.n = n;}@Overridepublic String call() throws Exception {// 描述线程的任务,返回线程执行返回后的结果// 需求:求1-n的和返回int sum = 0;for (int i=1;i<n;i++){sum+=i;}return ""+sum;}
}

(2)把Callable类型的对象封装成FutureTask(线程任务对象)

//创建一个Callable对象Callable<String> call = new MyCall(100);

2.把线程任务对象交给Thread对象

// 把Callable的对象封装成一个FutureTask对象// 未来任务对象的作用?// 1.是一个任务对象,实现Runnable对象// 2.可以在线程执行完毕后,// 用未来线程对象调用get方法获取线程执行完毕后值FutureTask<String> f1 = new FutureTask<>(call);

3.调用Thread对象的start方法启动线程

// 把任务对象交给一个Thread对象new Thread(f1).start();

4.线程执行完毕后,通过FutureTask对象的get()方法去获取线程任务执行的结果

// 获取线程执行完毕后返回的结果// 注意: 如果执行到这,假如说线程还没有执行完毕// 这里的代码会暂停,等待上面线程执行完毕后才会获取结果String s = f1.get();System.out.println(s);

mian主线程中的完整代码


import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class main_Thread {public static void main(String[] args) throws Exception {//创建一个Callable对象Callable<String> call = new MyCall(100);// 把Callable的对象封装成一个FutureTask对象// 未来任务对象的作用?// 1.是一个任务对象,实现Runnable对象// 2.可以在线程执行完毕后,// 用未来线程对象调用get方法获取线程执行完毕后值FutureTask<String> f1 = new FutureTask<>(call);// 把任务对象交给一个Thread对象new Thread(f1).start();// 获取线程执行完毕后返回的结果// 注意: 如果执行到这,假如说线程还没有执行完毕// 这里的代码会暂停,等待上面线程执行完毕后才会获取结果String s = f1.get();System.out.println(s);}
}

Thread方法

public class main_Thread {public static void main(String[] args) throws Exception {Thread t1 = new MyThread();t1.setName("1号线程");t1.start();System.out.println(t1.getName()); // 输出线程1的名字Thread t2 = new MyThread();t2.setName("2号线程");t2.start();System.out.println(t2.getName()); // 输出线程2的名字// 主线程对象的名字Thread m = Thread.currentThread(); // 拿到当前执行线程名字m.setName("nb线程");System.out.println(m.getName()); // mainfor (int i = 0; i <= 5; i++) {System.out.println("main主线程输出:"+i);}}
}
public class ThreadTest {public static void main(String[] args) throws InterruptedException {for (int i = 0; i <=5 ; i++) {if(i== 3){// 让当前的线程停止5秒Thread.sleep(5000);}}// join方法让调用方法的线程先执行完Thread t1 = new Thread();t1.start();t1.join();}
}

线程安全

线程安全问题的原因: 多个线程,同时访问同一个共享资源,且存在修改资源

我们来模拟线程安全,假如说现在取钱,小明和小红在同一个账户下取钱,现在账户有10万元,小明在他的手机上取10万元,小红在她的手机取10万元,想有没有一种可能小明的手机判断有钱但是还没有取钱的同时,小红的手机也判断有钱,也要完成取钱操作,这样的话小明取出来了10万元,小红手机也取出了10万元,而账户中只有10万元,这就是线程安全

我们用代码模拟一下这个情况

我们先创建账户类,用来创建账户对象

package surf_Thread;public class Account {private String Id;private int money;public Account() {}public Account(String id, int money) {Id = id;this.money = money;}public String getId() {return Id;}public void setId(String id) {Id = id;}public int getMoney() {return money;}public void setMoney(int money) {this.money = money;}public void drawMoney(int i) {// 先搞清楚谁来取钱?String name = Thread.currentThread().getName();// 判断余额是否足够if(this.money>=i){System.out.println(name+"来取钱"+money+"成功");this.money-=i;System.out.println(name+"来取钱后,余额剩余: "+money);}else{System.out.println(name + "来取钱,余额不足");}}
}

我们在上面创建了一个类的取钱方法,因为每个线程都要进入这个方法,我们可以拿到这个线程的名字

下面我们创建一个线程类,run里面要把握住,这个线程的行为,因为我们要完成取钱,所以必须有一个账户对象,我们要构建一个有参构造器,来接收对那个账户进行操作,还要接受线程的名字

package surf_Thread;public class DrawMoney extends Thread{private Account acc;public DrawMoney(Account acc,String name){super(name); // super 要放到上面this.acc = acc;}@Overridepublic void run(){//run里面主要实现线程要完成什么事情acc.drawMoney(100000);}
}

主线程

package surf_Thread;public class ThreadTest {public static void main(String[] args) {// 1. 创建一个账户,两个人共同的对象Account acc = new Account("ICBC-120",100000);// 2.创建取钱线程new DrawMoney(acc,"小明").start();new DrawMoney(acc,"小红").start();}
}

我们对这个案例运行时,发现:

这个就会造成线程安全问题

我们应该怎么解决呢?

看下面

线程同步

同步代码块

建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象

对于静态方法建议使用字节码(类名.class)对象作为锁对象

同步方法

有隐含this

Lock锁

线程池

JDK 5.0起提供了代表线程池的接口: ExecutorService

但是利用接口我们是不能创建线程池对象的,那我们如何得到线程池对象?

线程池对象的创建方式一:

使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象

需要我们注意的是:

1.临时线程什么时候创建?

新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程

2.什么时候会开始拒绝新任务?

核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务

下面是创建线程池

import java.util.concurrent.*;public class Pool {public static void main(String[] args) {ExecutorService Pool = new ThreadPoolExecutor(3,5,8, TimeUnit.SECONDS,new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());}
}

线程池处理Runnable任务

下面是4中不同形式的任务拒绝策略

public class Pool {public static void main(String[] args) {ExecutorService Pool = new ThreadPoolExecutor(3,5,8, TimeUnit.SECONDS,new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());Runnable target = new MyRunnable();Pool.execute(target); // 线程池自动创建一个新线程,自动处理这个任务,自动执行Pool.execute(target); // 线程池自动创建一个新线程,自动处理这个任务,自动执行Pool.execute(target); // 线程池自动创建一个新线程,自动处理这个任务,自动执行Pool.execute(target); // 复用上面的线程Pool.execute(target); // 复用上面的线程 // 注意临时线程的创建条件:核心线程都占用了,而且队列中都占满了// 如果想要创建临时线程,让上面的线程都被占用,而且队列占满//假如说现在满足条件,那么下面添加任务就开始创建临时线程Pool.execute(target);Pool.execute(target);  // 上面创建了两个临时线程// 如果再有任务那么就直接拒绝}
}

因为线程池创建之后开始运行,他不能自动关闭,我们一般情况下也不希望它关闭

那么怎么让他关闭呢?

两种方法:

线程池处理Callable任务

package ThreadPoolTest;import java.util.concurrent.*;public class Pool {public static void main(String[] args) throws Exception {ExecutorService Pool = new ThreadPoolExecutor(3,5,8, TimeUnit.SECONDS,new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());Future<String> f1 = Pool.submit(new MyCall(100));Future<String> f2 = Pool.submit(new MyCall(200));Future<String> f3 = Pool.submit(new MyCall(300));String s1 = f1.get();}
}

并发和并行

进程: 正在运行的程序(软件)就是独立的进程

线程是属于进程的,一个进程中可以同时运行很多个线程

进程中的多个线程其实是并发和并行的

并发的含义

进程中的线程是由CPU负责执行的,但CPU能同时处理的线程数量有限,为保证全部线程都能往前执行,CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发

并行的理解

在同一个时刻上,同时有多个线程在被CPU调度执行

线程的六种状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/181189.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BGP综合实验

任务如下&#xff1a; 1.AS1存在两个环回&#xff0c;一个地址为192.168.1.0/24该地址不能在任何协议中宣告 AS3存在两个环回&#xff0c;一个地址为192.168.2.0/24该地址不能在任何协议中宣告&#xff0c;最终要求这两个环回可以互相通讯 2.整个AS2的IP地址为172.16.0.0/16&…

Sentaurus TCAD半导体器件入门常用案例合集

Sentaurus TCAD是用于模拟半导体器件和工艺的工具之一&#xff0c;可以帮助工程师设计电路元件&#xff0c;优化半导体工艺和器件性能。主要功能包括&#xff1a;半导体器件建模&#xff08;用于建立各种半导体器件的物理模型工艺模拟&#xff09;、半导体器件的制造工艺模拟&a…

Debian10安装VMware Tools

一、原系统 首先我在界面按CTRLALTT和CTRLSiftT都没有反应&#xff0c;没关系&#xff0c;我有办法 系统版本 管理员用户 步骤一&#xff1a;打开VMware Tools文件 步骤二、将文件复制到自己熟悉的文件内 步骤三、命令行查看文件是否复制成功存在 步骤四、解压VMware-tools…

宋仕强论道之华强北的商业配套(十三)

宋仕强论道之华强北的商业配套&#xff08;十三&#xff09;&#xff1a;金航标电子萨科微半导体总经理宋仕强先生发布“宋仕强论道”系列视频&#xff0c;分享多年学习、生活和工作经验和感悟&#xff0c;甚至涵盖了文学、艺术、哲学、宗教。这段时间发表的是对华强北&#xf…

程序设计基础中可能出现的简单编程题2(以郑大为主体)

我们在学习编程过程中往往不仅有C语言实验报告&#xff0c;还有程序设计实验报告。程序设计这一科目主要是为了培养我们写代码时的计算思维&#xff0c;养成从问题到代码实现逐步分析&#xff0c;逐步深入的好习惯。前面有一篇文章介绍了部分程序设计实验报告中的编程题&#x…

第二十章 -----多线程

20.1 线程简介 计算机完全可以将多种活动同时进行&#xff0c;这种思想在java中称为并发&#xff0c;将并发完成的每一件事情称为线程 线程的特点&#xff1a; 极小的单位 一个进程有很多个线程 线程共享进程的资源 20.2 创建线程 20.2.1 继承Thread类 Thread类是Java.l…

Python实现视频人脸检测识别功能

目录 一、引言 二、人脸检测识别技术概述 三、Python实现视频人脸检测识别功能的步骤 1、安装相关库和工具 2、加载视频文件 3、人脸检测和识别 4、保存视频结果 四、实验结果和讨论 五、结论 一、引言 在当今社会&#xff0c;人脸检测识别技术在安全监控、人机交互、…

全网日志智能聚合及问题根因分析

1 日志关联分析的挑战 随着各行各业数字化转型的不断深入&#xff0c;网络承载了人们日常生活所需的政务、金融、娱乐等多方面的业务系统&#xff0c;已经成为影响社会稳定运行、关系国计民生的重要基础设施资源。哪怕网络发生及其微小的故障&#xff0c;也可能带来难以估量的…

Java基础之原码,反码,补码,位运算符

文章目录 前言一、二进制在运算中介绍二、原码&#xff0c;反码&#xff0c;补码&#xff08;针对有符号的&#xff09;三、位运算符按位与&按位或 |按位异或 ^按位取反 ~算术右移>>算术左移<<逻辑右移>>> 总结 前言 原码&#xff0c;反码&#xff0…

【shell】文本三剑客之sed详解

目录 一、sed简介&#xff08;行编辑器&#xff09; 二、基本用法 三、sed脚本格式&#xff08;匹配地址 脚本命令&#xff09; 1、不给地址&#xff0c;那么就是针对全文处理 2、单地址&#xff0c;表示#&#xff0c;指定的行&#xff0c;$表示最后一行&#xff0c;/pattt…

牛客算法题 HJ100 等差数列 golang语言实现

算法题目 HJ100 等差数列 描述 等差数列 2&#xff0c;5&#xff0c;8&#xff0c;11&#xff0c;14。。。。 &#xff08;从 2 开始的 3 为公差的等差数列&#xff09; 输出求等差数列前n项和数据范围&#xff1a; 1 ≤ &#xfffd; ≤ 10001≤n≤1000 输入描述&#xff…

python与机器学习1,机器学习的一些基础知识概述(完善ing)

目录 1 AI ,ML,DL,NN 等等概念分类 1.1 人工智能、机器学习、深度学习、神经网络之间的关系&#xff1a; 1.2 人工智能的发展 2 ML机器学习的分类&#xff1a;SL, USL,RL 2.1 机器学习的分类 2.2 具体的应用举例 2.3 数据分类 3 关于阈值θ和偏移量b的由来 4 不同的激…

网站定制开发对企业的好处|软件app小程序搭建

网站定制开发对企业的好处|软件app小程序搭建 在当今数字化的时代&#xff0c;拥有一个专属于自己企业的网站已经成为了一种趋势。而与此同时&#xff0c;网站定制开发作为一种针对企业需求量身定制的解决方案&#xff0c;也越来越受到企业的关注和青睐。那么&#xff0c;网站定…

SSL证书实惠品牌——JoySSL

随着互联网的普及和发展&#xff0c;网络安全问题日益严重。为了保护网站数据的安全&#xff0c;越来越多的网站开始使用SSL证书。JoySSL证书作为一款高性价比的SSL证书&#xff0c;受到了广泛的关注和好评。 目前市面上主流的证书基本上都是国外证书&#xff0c;也就是说你在验…

HarmonyOS 后台任务管理开发指南上线!

为什么要使用后台任务&#xff1f;开发过程中如何选择合适的后台任务&#xff1f;后台任务申请时存在哪些约束与限制&#xff1f; 针对开发者使用后台任务中的疑问&#xff0c;我们上线了概念更明确、逻辑结构更清晰的后台任务开发指南&#xff0c;包含具体的使用场景、详细的开…

js实现鼠标拖拽

目录 css代码 html代码 js代码 完整代码 效果图&#xff1a; 需求&#xff1a; 鼠标在图片内按下时 图片可以跟随盒子动 鼠标弹起图片停下来 如果图片在box的盒子里面时鼠标弹起了 就把图片展示在box里面 并且让图片回到起始位置 css代码 .div {width: 100px;height: 10…

五分钟 k8s 实战-应用探针

Probe.png 今天进入 kubernetes 的运维部分&#xff08;并不是运维 kubernetes&#xff0c;而是运维应用&#xff09;&#xff0c;其实日常我们大部分使用 kubernetes 的功能就是以往运维的工作&#xff0c;现在云原生将运维和研发关系变得更紧密了。 今天主要讲解 Probe 探针相…

C语言——I /深入理解指针(三)

一、字符指针变量 在指针的类型中我们知道有⼀种指针类型为字符指针 char* ; ⼀般使⽤: int main() { char ch w; char *pc &ch; *pc w; return 0; } 还有⼀种使⽤⽅式如下&#xff1a; int main() { const char* pstr "hello bit.";//这⾥是把⼀个字…

jquery 地址四级联级显示 不默认选择

代码效果 <body class"bgca"><img src"./files/joinTooBg.png" style"width: 100%;object-fit: cover;" alt""><!--填写申请资料--><section><div class"zi-liao"><h3 class"zong-h…

鸿蒙应用开发之打包与上架

一、概述 当您开发、调试完HarmonyOS应用/元服务&#xff0c;就可以前往AppGallery Connect申请上架&#xff0c;华为审核通过后&#xff0c;用户即可在华为应用市场获取您的HarmonyOS应用/元服务。 HarmonyOS会通过数字证书与Profile文件等签名信息来保证应用的完整性&#…