java多线程编程实战指南核心篇,java hashset
- 软件开发
- 2023-09-07
- 124
大家好,关于java多线程编程实战指南核心篇很多朋友都还不太明白,今天小编就来为大家分享关于java hashset的知识,希望对各位有所帮助!为什么Java坚持多线程...
大家好,关于java多线程编程实战指南核心篇很多朋友都还不太明白,今天小编就来为大家分享关于java hashset的知识,希望对各位有所帮助!
为什么Java坚持多线程不选择协程
从java被发明的第一天起,就被定义为一个多线程的网络编程语言。Java最大特点并不是跨平台,而是它的多线程模型(那时候的C++中,并没有我们现在看到的thread,C#还没有出来)。因为近二十年的软件行业的增长主要来自网络编程,网络编程最常见的模型就是client/server,也就是所谓的C/S,这种编程模型在服务器端需要同时接受客户端的请求,也就是说要有很好的并发特性--这个特性主要依赖多线程来实现。而java的主战场就是服务器端编程。所以多线程对java是极为重要,不可或缺的一环。
当我们希望引入协程,我们想解决什么问题。我想不外乎下面几点:
节省资源,轻量,具体就是:节省内存,每个线程需要分配一段栈内存,以及内核里的一些资源节省分配线程的开销(创建和销毁线程要各做一次syscall)节省大量线程切换带来的开销与NIO配合实现非阻塞的编程,提高系统的吞吐使用起来更加舒服顺畅(async+await,跑起来是异步的,但写起来感觉上是同步的)我们分开来讲下。
先说内存。拿JavaWeb编程举例子,一个tomcat上的woker线程池的最大线程数一般会配置为50~500之间(目前springboot的默认值给的200)。也就是说同一时刻可以接受的请求最多也就是这么多。如果超过了最大值,请求直接打失败拒绝处理。假如每个线程给128KB,500个线程放一起的内存占用量大概是60+MB。如果真的有瓶颈,也许CPU,IO,带宽,DB的CPU等会有瓶颈,但这点内存量的增幅对于动辄数个GB的Java运行时进程来说似乎并不是什么大问题。
推荐几本非常棒的Java多线程编程书籍
1、《Java并发编程实战》
2、《Java多线程编程核心技术》
3、《Java多线程编程实战指南》
4、《Java并发编程的艺术》
专业从事软件研发工作多年,在软件设计、开发、测试、研发管理等领域里经验丰富,感兴趣的朋友可以关注我的头条号,相信一定会有所收获。如果有软件研发方面的问题,可以咨询我。谢谢!
开发多线程的程序应该注意哪些问题
要想回答这个问题,首先我们必须知道线程的概念、线程的运行特点以及多线程可能产生的问题及对应的解决方案。
首先,线程是计算机执行任务的基本单位,线程的集合是进程,通常系统调度任务是以进度为单位的,线程需要程序员自己编写。线程由三个组成部分,分别是线程操作代码、CPU时间、操作的数据。
线程在执行过程中通常会经历不同的阶段和状态,总的来说就是“三池两态”。所谓的“三池”就是就绪池、运行池、阻塞池,两态指的是起始态和终止态。一个线程从创建到被被回收都离不开这几个阶段。多线程的执行还存在执行规则的问题,是采用时间片还是优先级,时间片考虑的是公平原则,而优先级则体现了任务的轻重缓急,很多系统兼顾了两个原则,比如windows系统的任务调度就是这种方式。
清楚线程如何在不同状态的转换条件是使用线程的前提,而线程操作数据导致的同步问题则是线程使用过程中的核心问题。线程在操作共享数据时可能会产生的三个主要问题是竞态条件、数据竞争和缓存变量,解决这三个问题的方案就是采用临界区同步。不同的语言使用的方式不同,在java中采用的是synchronized进行同步区域界定。
由多线程引发的问题比如生产者-消费者问题阐述了线程之间的依赖关系,定时器描述了特定线程任务的执行,线程同步器描述了多个线程解决问题的流程安排以及多线程数据交换等问题,多线程并发能力是衡量系统性能的重要指标,所以系统架构设计必须充分考虑多线程并发的设计。
我在头条写了关于java多线程并发的系列文章,详细阐述了java进行多线程并发编程所涉及到的问题,以及相应的解决方案,每篇文章都有对应的程序案例。关注我就能看到这些文章,欢迎大家一起交流!
感谢邀请!
多线程编程中锁如何保证自己是线程安全的
线程安全问题概述卖票问题分析单窗口卖票
一个窗口(单线程)卖100张票没有问题
单线程程序是不会出现线程安全问题的
多个窗口卖不同的票3个窗口一起卖票,卖的票不同,也不会出现问题
多线程程序,没有访问共享数据,不会产生问题
多个窗口卖相同的票3个窗口卖的票是一样的,就会出现安全问题
多线程访问了共享的数据,会产生线程安全问题
线程安全问题代码实现模拟卖票案例
创建3个线程,同时开启,对共享的票进行出售
线程安全问题原理分析线程安全问题产生原理图
分析:线程安全问题正常是不允许产生的,我们可以让一个线程在访问共享数据的时候,无论是否失去了cpu的执行权;让其他的线程只能等待,等待当前线程卖完票,其他线程在进行卖票。
解决线程安全问题办法1-synchronized同步代码块同步代码块:synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
使用synchronized同步代码块格式:
synchronized(锁对象){可能会出现线程安全问题的代码(访问了共享数据的代码)}
代码实现如下:
注意:
代码块中的锁对象,可以使用任意的对象。但是必须保证多个线程使用的锁对象是同一个。锁对象作用:把同步代码块锁住,只让一个线程在同步代码块中执行。同步技术原理分析同步技术原理:
使用了一个锁对象,这个锁对象叫同步锁,也叫对象锁,也叫对象监视器
3个线程一起抢夺cpu的执行权,谁抢到了谁执行run方法进行卖票。
t0抢到了cpu的执行权,执行run方法,遇到synchronized代码块这时t0会检查synchronized代码块是否有锁对象发现有,就会获取到锁对象,进入到同步中执行
t1抢到了cpu的执行权,执行run方法,遇到synchronized代码块这时t1会检查synchronized代码块是否有锁对象发现没有,t1就会进入到阻塞状态,会一直等待t0线程归还锁对象,t0线程执行完同步中的代码,会把锁对象归还给同步代码块t1才能获取到锁对象进入到同步中执行
总结:同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进不去同步。
解决线程安全问题办法2-synchronized普通同步方法同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。
格式:
publicsynchronizedvoidpayTicket(){可能会出现线程安全问题的代码(访问了共享数据的代码)}
代码实现:
分析:定义一个同步方法,同步方法也会把方法内部的代码锁住,只让一个线程执行。
同步方法的锁对象是谁?
就是实现类对象newRunnableImpl(),也是就是this,所以同步方法是锁定的this对象。
解决线程安全问题办法3-synchronized静态同步方法同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。
格式:
publicstaticsynchronizedvoidpayTicket(){可能会出现线程安全问题的代码(访问了共享数据的代码)}
代码实现:
分析:静态的同步方法锁对象是谁?
不能是this,this是创建对象之后产生的,静态方法优先于对象
静态方法的锁对象是本类的class属性–>class文件对象(反射)。
解决线程安全问题办法4-Lock锁Lock接口中的方法:
publicvoidlock():加同步锁。publicvoidunlock():释放同步锁使用步骤:
在成员位置创建一个ReentrantLock对象在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁代码实现:
分析:java.util.concurrent.locks.Lock接口
Lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:
等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过lock.lockInterruptibly()来实现这个机制。公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。公平锁、非公平锁的创建方式:
锁绑定多个条件,一个ReentrantLock对象可以同时绑定多个对象。ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。ReentrantLock和Synchronized的区别相同点:
它们都是加锁方式同步;都是重入锁;阻塞式的同步;也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,不过可以通过对锁优化进行改善);实际工作中,什么场景会用到多线程开发
最典型的应用比如tomcat,tomcat内部采用的就是多线程,上百个客户端访问同一个web应用,tomcat接入后都是把后续的处理扔给一个新的线程来处理,这个新的线程最后调用到我们的servlet程序,比如doGet或者doPost方法。
如果不采用多线程机制,上百个人同时访问一个web应用的时候,tomcat就得排队串行处理了,那样客户端根本是无法忍受那种访问速度的。
还有就是需要异步处理的时候,需要使用多线程。比如taska和taskb要并行处理,单个线程只能串行处理,先做完taska然后再做taskb。如果想要多个task同时执行的话,就必须为每个task分配一个线程,然后通过java虚拟机的线程调度,来同时执行多个任务。比如你的CPU是多核心的话,就可以让一个CPU执行一个线程。如果只有一个CPU的话,底层是按照分时复用的原则,各个线程按照时间片来获得CPU资源。
关于java多线程编程实战指南核心篇,java hashset的介绍到此结束,希望对大家有所帮助。
本文链接:http://xinin56.com/ruanjian/16718.html