Java并发 —— 线程并发(一)
线程和进程
进程就是一个内存中运行的应用程序
线程是当前进程中的一个执行任务(控制单元),负责当前进程中程序的执行
区别与联系
根本区别:进程是操作系统资源分配的基本单位,线程是处理器任务调度和执行的基本单位
包含关系:一个进程可以有多个线程,至少有一个
内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
影响关系:一个进程崩溃后,在保护模式下,不会对其他进程产生影响,而一个线程崩溃后,整个进程都会死掉,所以多进程比多线程健壮
执行过程:每个进程都有独立的程序运行入口、顺序执行序列和程序出口,而线程不能独立执行,必须依存在应用程序中
线程的生命周期
新建:当程序创建一个线程后,线程就处于新建状态,此时由 JVM 为其分配内存,并初始化其成员变量的值
就绪:当线程对象调用
start()方法后,线程就处于就绪状态,JVM 会为其创建方法调用栈和程序调度器,等待调度运行运行:处于就绪状态的线程获得了 CPU,开始执行
run()方法的线程执行体,此时该线程就处于运行状态start()和run()的区别start()方法来启动线程,实现了多线程运行,无需等待run方法体代码执行完毕,可以直接继续执行下面的代码调用
start()方法启动线程,线程会进入就绪状态,而非运行方法
run()被称为线程体,包含了要执行线程的内容,线程会进入运行状态,执行run方法体中的代码,方法运行结束,线程终止,CPU 再调度其他线程
阻塞:线程因为某种原因放弃了 CPU 使用权,暂时停止运行,此时线程处于阻塞状态
等待阻塞:运行的线程执行
wait()方法,JVM 会将该线程放入等待队列中同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被其他线程所占用,则 JVM 会将该线程放入锁池(lock pool)中
其他阻塞:运行的线程执行
sleep(long ms)或join()方法,或发出了I/O请求时,JVM 会将线程设置为阻塞状态。 当sleep()运行超时、join()等待线程终止或超时、或者I/O处理完毕时,线程可重新转入可运行状态
sleep()和wait()的区别sleep()方法是属于 Thread 类中的,而wait()方法则是属于 Object 类中sleep()方法导致了程序暂停执行指定的时间,让出 CPU 给其他线程,但是他的监控状态仍然保持,当指定时间到了又会回到运行状态;在调用sleep()的过程中,线程不会释放对象锁- 调用
wait()方法时,会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后,本线程才进入对象锁定池准备获取对象锁进入运行状态
死亡:线程结束后就是死亡状态,会以以下三种方式结束
正常结束:
run()或者call()方法执行完成,线程正常结束异常结束:线程抛出一个未捕获的
Exception或Error调用
stop:直接调用该线程的stop()方法来结束线程(该方法容易导致死锁,不推荐使用)
多线程
创建多线程方式
继承
Thread类
通过继承 Thread 类,重写其run()方法,run()方法中定义了线程执行的具体任务,创建该类的实例后,调用其start()方法来启动线程Thread 本质上是实现了 Runnable 接口的一个实例,代表线程的一个实例。

public class ThreadTest extends Thread{
@Override
public void run() {
System.out.println("ThreadTest");
}
} public class Main {
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
threadTest.start();
}
}
实现
Runnable接口
实现 Runnable 接口后,通过重写其run()方法,然后将此 Runnable 对象作为参数传递给 Thread 类的构造器,创建 Thread 对象后,调用其start()方法启动线程如果自己的类已经继承了一个类,由于Java是单继承的,所以没法用第一种方式,就可以通过实现 Runnable 接口创建多线程,在 Runnable 接口中只有一个
run()方法
public class ThreadTest implements Runnable{
@Override
public void run() {
System.out.println("Runnable");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new ThreadTest());
thread.start();
}
}
基于线程池的方式(Executor框架)
这是种更高效的线程管理方式,避免了频繁创建和销毁线程的开销,可以通过 Executor 类的静态方法创建不同类型的线程池public class ThreadTest implements Runnable{
@Override
public void run() {
System.out.println("Executor");
}
}
public class Main {
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
// 提交任务到线程池执行
executorService.submit(new ThreadTest());
}
// 关闭线程池
executorService.shutdown();
}
}
三种方式的优缺点
继承Thread类
优点:编写简单,如果要访问当前线程,无需使用
Thread.currentThread()方法,直接使用this即可缺点:Java的单继承,在继承了
Thread类后,不能再继承其他类了,有局限性
实现Runnable接口
优点:在实现了接口后,仍然可以继承其他类。在这种情况下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程处理同一份资源的情况,从而将CPU代码和数据分开,形成清晰的模型
缺点:编程较为复杂,如果需要访问当前线程,必须使用
Thread.currentThread()方法
线程池(Executor框架)
优点:线程池可以重用预先创建的线程,避免了线程创建和销毁的开销,提高程序的性能,对于快速响应的并发请求,线程池可以迅速提供线程来处理任务,减少等待时间。并且线程池可以有效控制运行的线程数量,防止创建过多的线程导致系统资源被耗尽(内存溢出),节约系统资源,可以最大化CPU利用率和系统吞吐率
缺点:增加了程序复杂度,特别是涉及到线程池参数调整和故障排查时,错误的配置可能导致资源耗尽、死锁等问题
四种线程池
Java中线程池的顶级接口是
Executor但严格意义上,Executor并不是一个线程池,它只是一个执行线程的工具,真正的线程池接口是ExecutorService
newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool: 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool:创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor:返回一个线程池(单一线程),在其他线程死后(或发生异常时),重新启动一个线程代替原来的线程执行下去
Java并发 —— 线程并发(一)的更多相关文章
- Java使用线程并发库模拟弹夹装弹以及发射子弹的过程
同样是从网上看到的一个需求,需求描述都在代码中. 不多说了,直接贴代码了.相信大家都能够看得懂的! package cn.yw.bore; import java.util.ArrayList; im ...
- 【Linux】线程并发拷贝程序
据说大连某211高校的李教授越来越重口.不仅延续要求他所带的每个本科班.都要写一份线程并发拷贝程序的传统,并且还開始规定不能用Java语言写作.导致我之前写的<[Java]线程并发拷贝程序> ...
- Shell-使用mkfifo实现多任务并发及并发数控制
以下为代码实现的一个模拟场景:3个生产者,在不断提供服务,处理需求,假设1s处理一个. 20个消费者,在不断消耗供给产品,提交需求,假设3s消耗一个. 情景分析:由于消费者的提交需求能力 和 生产者处 ...
- Java线程并发:知识点
Java线程并发:知识点 发布:一个对象是使它能够被当前范围之外的代码所引用: 常见形式:将对象的的引用存储到公共静态域:非私有方法中返回引用:发布内部类实例,包含引用. 逃逸:在对象尚未准备 ...
- Java线程并发中常见的锁
随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题.本文着重介绍了在java并发中常见的几种锁机制. 1.偏向锁 偏向锁是JDK1.6提出来的一种锁优化的机制.其核心的思想 ...
- Java多线程与并发库高级应用-java5线程并发库
java5 中的线程并发库 主要在java.util.concurrent包中 还有 java.util.concurrent.atomic子包和java.util.concurrent.lock子包 ...
- Java 线程并发策略
1 什么是并发问题. 多个进程或线程同时(或着说在同一段时间内)访问同一资源会产生并发问题. 2 java中synchronized的用法 用法1 public class Test{ public ...
- Java并发——线程安全、线程同步、线程通信
线程安全 进程间"共享"对象 多个“写”线程同时访问对象. 例:Timer实例的num成员,即add()方法是用的次数.即Timer实例是资源对象. class TestSync ...
- Java线程并发中常见的锁--自旋锁 偏向锁
随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题.本文着重介绍了在java并发中常见的几种锁机制. 1.偏向锁 偏向锁是JDK1.6提出来的一种锁优化的机制.其核心的思想 ...
- Java 并发 线程同步
Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大 ...
随机推荐
- EF Core – Soft Delete 实现
前言 在 SQL Server – Soft Delete 中, 讲到了如果在 SQL Server 实现 Soft Delete. 这篇来说说, EF Core 在中间扮演的角色. 主要参考 Ent ...
- HTML——基础标签
基础标签 图片.音频.视频标签 src:资源路径 1.绝对路径 2.相对路径 ./ 表示本级目录 (可以省略) ../ 表示上级目录 超链接标签 列表标签 表格标签 ...
- Flutter Engage China 开发者常见问题解答 | 上篇
再次感谢大家对 Flutter Engage China 活动 的关注和积极参与!我们在活动前后收到了很多来自开发者的反馈和问题,Flutter 团队和演讲嘉宾在直播 Q&A 环节中也针对部分 ...
- 禁用QQ自动升级(实测可用)
事件起因: 某客户电脑QQ从怀旧版(9.7)自动升级到NT版本(9.9)版本,新版本由于消息通知功能不能直接查看,老版本右下角消息闪烁,鼠标放上去便可以看到有几个联系人的消息,因此客户强烈要求版本回退 ...
- 【赵渝强老师】MySQL的闪回
MySQL DBA或开发人员,有时会误删或者误更新数据,如果是线上环境并且影响较大,就需要能快速回滚.传统恢复方法是利用备份重搭实例,再应用去除错误sql后的binlog来恢复数据.此法费时费力,甚至 ...
- 17 模块subprocess、re
1. subprocess模块 1.1 概念 subprocess模块启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值 简单理解:可以远程连接电脑(socket模块) 1.2 Pop ...
- 如何理解iowait
Linux中,%iowait 过高可能是个问题,严重的时候,它能使服务停止, 但问题是,多高才算高? 什么时候应该担心呢? 本文将讨论 iowait 的含义.相关的统计数据.原理以及 iowait的瓶 ...
- Makefile优化编译速度
并行编译:使用 make -j 命令来进行并行编译,可以加快编译速度.-j 后面可以跟一个数字,表示并行编译的线程数. 懒惰计算:使用 .PHONY 规则来避免无谓的重新编译.该规则告诉 make,这 ...
- gaussian噪声
高斯噪声 高斯噪声(Gaussian noise)是一种具有正态分布(也称作高斯分布)概率密度函数的噪声.换句话说,高斯噪声的值遵循高斯分布或者它在各个频率分量上的能量具有高斯分布.它被极其普遍地应用 ...
- plt.gca()坐标轴移动
我们可以看到绘制出来的图有四个边框,我们通过gca()对坐标轴进行一些简单处理,代码如下. import torch import torch.nn.functional as F import ma ...