文章编号:11434时间:2024-09-30人气:
线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源、什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些原则问题需要考虑,是否有竞争资源被同时改动的问题?对于同步,在具体的Java代码中需要完成以下两个操作:把竞争访问的资源标识为private;同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。
当然这不是唯一控制并发安全的途径。
synchronized关键字使用说明synchronized只能标记非抽象的方法,不能标识成员变量。
为了演示同步方法的使用,构建了一个信用卡账户,起初信用额为100w,然后模拟透支、存款等多个操作。
显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(int x),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。
工作原理线程是进程中的实体,一个进程可以拥有多个线程,一个线程必须有一个父进程。
线程不拥有系统资源,只有运行必须的一些数据结构;它与父进程的其它线程共享该进程所拥有的全部资源。
线程可以创建和撤消线程,从而实现程序的并发执行。
一般,线程具有就绪、阻塞和运行三种基本状态。
在多中央处理器的系统里,不同线程可以同时在不同的中央处理器上运行,甚至当它们属于同一个进程时也是如此。
大多数支持多处理器的操作系统都提供编程接口来让进程可以控制自己的线程与各处理器之间的关联度(affinity)。
有时候,线程也称作轻量级进程。
就象进程一样,线程在程序中是独立的、并发的执行路径,每个线程有它自己的堆栈、自己的程序计数器和自己的局部变量。
但是,与分隔的进程相比,进程中的线程之间的隔离程度要小。
它们共享内存、文件句柄和其它每个进程应有的状态。
进程可以支持多个线程,它们看似同时执行,但互相之间并不同步。
一个进程中的多个线程共享相同的内存地址空间,这就意味着它们可以访问相同的变量和对象,而且它们从同一堆中分配对象。
尽管这让线程之间共享信息变得更容易,但您必须小心,确保它们不会妨碍同一进程里的其它线程。
Java 线程工具和 API看似简单。
但是,编写有效使用线程的复杂程序并不十分容易。
因为有多个线程共存在相同的内存空间中并共享相同的变量,所以您必须小心,确保您的线程不会互相干扰。
线程属性为了正确有效地使用线程,必须理解线程的各个方面并了解Java 实时系统。
必须知道如何提供线程体、线程的生命周期、实时系统如 何调度线程、线程组、什么是幽灵线程(Demo nThread)。
线程体所有的操作都发生在线程体中,在Java中线程体是从Thread类继承的run()方法,或实现Runnable接口的类中的run()方法。
当线程产生并初始化后,实时系统调用它的run()方法。
run()方法内的代码实现所产生线程的行为,它是线程的主要部分。
线程状态附图表示了线程在它的生命周期内的任何时刻所能处的状态以及引起状态改变的方法。
这图并不是完整的有限状态图,但基本概括了线程中比较感兴趣和普遍的方面。
以下讨论有关线程生命周期以此为据。
●新线程态(New Thread)产生一个Thread对象就生成一个新线程。
当线程处于新线程状态时,仅仅是一个空线程对象,它还没有分配到系统资源。
因此只能启动或终止它。
任何其他操作都会引发异常。
例如,一个线程调用了new方法之后,并在调用start方法之前的处于新线程状态,可以调用start和sTOP方法。
●可运行态(Runnable)start()方法产生运行线程所必须的资源,调度线程执行,并且调用线程的run()方法。
在这时线程处于可运行态。
该状态不称为运行态是因为这时的线程并不总是一直占用处理机。
特别是对于只有一个处理机的PC而言,任何时刻只能有一个处于可运行态的线程占用处理 机。
Java通过调度来实现多线程对处理机的共享。
注意,如果线程处于Runnable状态,它也有可能不在运行,这是因为还有优先级和调度问题。
●阻塞/非运行态(Not Runnable)当以下事件发生时,线程进入非运行态。
①suspend()方法被调用;②sleep()方法被调用;③线程使用wait()来等待条件变量;④线程处于I/O请求的等待。
●死亡态(Dead)当run()方法返回,或别的线程调用stop()方法,线程进入死亡态。
通常Applet使用它的stop()方法来终止它产生的所有线程。
线程的本操作:派生:线程在进程内派生出来,它即可由进程派生,也可由线程派生。
阻塞(Block):如果一个线程在执行过程中需要等待某个事件发生,则被阻塞。
激活(unblock):如果阻塞线程的事件发生,则该线程被激活并进入就绪队列。
调度(schedule):选择一个就绪线程进入执行状态。
结束(Finish):如果一个线程执行结束,它的寄存器上下文以及堆栈内容等将被释放。
图2 线程的状态与操作线程的另一个执行特性是同步。
线程中所使用的同步控制机制与进程中所使用的同步控制机制相同。
线程优先级虽然我们说线程是并发运行的。
然而事实常常并非如此。
正如前面谈到的,当系统中只有一个CPU时,以某种顺序在单CPU情况下执行多线程被称为调度(scheduling)。
Java采用的是一种简单、固定的调度法,即固定优先级调度。
这种算法是根据处于可运行态线程的相对优先级来实行调度。
当线程产生时,它继承原线程的优先级。
在需要时可对优先级进行修改。
在任何时刻,如果有多条线程等待运行,系统选择优先级最高的可运行线程运行。
只有当它停止、自动放弃、或由于某种原因成为非运行态低优先级的线程才能运行。
如果两个线程具有相同的优先级,它们将被交替地运行。
Java实时系统的线程调度算法还是强制性的,在任何时刻,如果一个比其他线程优先级都高的线程的状态变为可运行态,实时系统将选择该线程来运行。
一个应用程序可以通过使用线程中的方法setPriority(int),来设置线程的优先级大小。
有线程进入了就绪状态,需要有线程调度程序来决定何时执行,根据优先级来调度。
线程中的join()可以用来邀请其他线程先执行(示例代码如下);publicclassJoin01implementsRunnable{publicstaticvoidmain(String[]args){for(inti=0;i<20;i++){if(i==5){Join01j=newJoin01();Threadt=newThread(j);(被邀请先执行的线程.);();try{//邀请这个线程,先执行();}catch(InterruptedExceptione){();}}(没被邀请的线程。
+(i+1));}}publicvoidrun(){for(inti=0;i<10;i++){(()()+(i+1));}}}yield()告诉系统把自己的CPU时间让掉,让其他线程或者自己运行,示例代码如下;publicclassYield01{publicstaticvoidmain(String[]args){YieldFirstyf=newYieldFirst();YieldSecondys=newYieldSecond();YieldThirdyt=newYieldThird();();();();}}classYieldFirstextendsThread{@Overridepublicvoidrun(){for(inti=0;i<10;i++){(第一个线程第+(i+1)+次运行.);//让当前线程暂停yield();}}}classYieldSecondextendsThread{@Overridepublicvoidrun(){for(inti=0;i<10;i++){(第二个线程第+(i+1)+次运行.);//让当前线程暂停yield();code原语,是JVM依赖操作系统互斥(mutex)来实现的。
而互斥是一种会导致线程挂起,并在较短的时间内又需要重新调度回原线程的,较为消耗资源的操作。
所以需要进行对线程进行优化,提高效率。
轻量级锁轻量级锁(Lightweight Locking)是从Java6开始引入的概念,本意是为了减少多线程进入互斥的几率,并不是要替代互斥。
它利用了CPU原语Compare-And-Swap(CAS,汇编指令CMPXCHG),尝试在进入互斥前,进行补救。
下面将详细介绍JVM如何利用CAS,实现轻量级锁。
Java Object Model中定义,Object Header是一个2字(1 word = 4 byte)长度的存储区域。
第一个字长度的区域用来标记同步,GC以及hash code等,官方称之为 mark word。
第二个字长度的区域是指向到对象的Class。
在2个word中,mark word是轻量级锁实现的关键,其结构见右表。
从表中可以看到,state为lightweight locked的那行即为轻量级锁标记。
bitfieds名为指向lock record的指针,这里的lock record,其实是一块分配在线程堆栈上的空间区域。
用于CAS前,拷贝object上的mark word。
第三项是重量级锁标记。
后面的状态单词很有趣,inflated,译为膨胀,在这里意思其实是锁已升级到OS-level。
一般我们只关注第二和第三项即可。
lock,unlock与mark word之间的联系如右图所示。
在图中,提到了拷贝object mark word,由于脱离了原始mark word,官方将它冠以displaced前缀,即displaced mark word(置换标记字)。
这个displaced mark word是整个轻量级锁实现的关键,在CAS中的compare就需要用它作为条件。
在拷贝完object mark word之后,JVM做了一步交换指针的操作,即流程中第一个橙色矩形框内容所述。
将object mark word里的轻量级锁指针指向lock record所在的stack指针,作用是让其他线程知道,该object monitor已被占用。
lock record里的owner指针指向object mark word的作用是为了在接下里的运行过程中,识别哪个对象被锁住了。
最后一步unlock中,我们发现,JVM同样使用了CAS来验证object mark word在持有锁到释放锁之间,有无被其他线程访问。
如果其他线程在持有锁这段时间里,尝试获取过锁,则可能自身被挂起,而mark word的重量级锁指针也会被相应修改。
此时,unlock后就需要唤醒被挂起的线程。
偏向锁Java偏向锁(Biased Locking)是Java 6引入的一项多线程优化。
它通过消除资源无竞争情况下的同步原语,进一步提高了程序的运行性能。
它与轻量级锁的区别在于,轻量级锁是通过CAS来避免进入开销较大的互斥操作,而偏向锁是在无竞争场景下完全消除同步,连CAS也不执行(CAS本身仍旧是一种操作系统同步原语,始终要在JVM与OS之间来回,有一定的开销)。
所谓的无竞争场景,就是单线程访问带同步的资源或方法。
偏向锁,顾名思义,它会偏向于第一个访问锁的线程,如果在接下来的运行过程中,该锁没有被其他的线程访问,则持有偏向锁的线程将永远不需要触发同步。
如果在运行过程中,遇到了其他线程抢占锁,则持有偏向锁的线程会被挂起,JVM会尝试消除它身上的偏向锁,将锁恢复到标准的轻量级锁。
(偏向锁只能在单线程下起作用)。
偏向模式和非偏向模式,在mark word表中,主要体现在thread ID字段是否为空。
挂起持有偏向锁的线程,这步操作类似GC的pause,但不同之处是,它只挂起持有偏向锁的线程(非当前线程)。
在抢占模式的橙色区域说明中有提到,指向当前堆栈中最近的一个lock record(在轻量级锁中,lock record是进入锁前会在stack上创建的一份内存空间)。
这里提到的最近的一个lock record,其实就是当前锁所在的stack frame上分配的lock record。
整个步骤是从偏向锁恢复到轻量级锁的过程。
偏向锁也会带来额外开销。
在JDK6中,偏向锁是默认启用的。
它提高了单线程访问同步资源的性能。
但试想一下,如果你的同步资源或代码一直都是多线程访问的,那么消除偏向锁这一步骤对你来说就是多余的。
事实上,消除偏向锁的开销还是蛮大的。
所以在你非常熟悉自己的代码前提下,大可禁用偏向锁 -XX:-UseBiasedLocking。
分类线程有两个基本类型:用户级线程:管理过程全部由用户程序完成,操作系统内核心只对进程进行管理。
系统级线程(核心级线程):由操作系统内核进行管理。
操作系统内核给应用程序提供相应的系统调用和应用程序接口API,以使用户程序可以创建、执行、撤消线程。
举例UNIX International 线程UNIX International 线程的头文件是
这个函数是主要用于调试器。 它并不打算用于线程同步。 在一个线程调用SuspendThread拥有一个同步对象,比如互斥或关键部分,会导致死锁如果调用线程试图获取同步对象属于一个暂停的线程。 为了避免这种情况,一个线程在一个应用程序,它不是一个调试器应该信号其他线程暂停本身
内容声明:
1、本站收录的内容来源于大数据收集,版权归原网站所有!
2、本站收录的内容若侵害到您的利益,请联系我们进行删除处理!
3、本站不接受违法信息,如您发现违法内容,请联系我们进行举报处理!
4、本文地址:http://www.jujiwang.com/article/c6de74de5b854c563809.html,复制请保留版权链接!
安卓应用签名是一种加密机制,用于验证安卓应用程序的身份和完整性,它是安卓安全生态系统中的一个关键部分,可防止恶意应用程序冒充合法应用程序并窃取用户数据或设备资源,安卓应用签名的工作原理当您开发一个安卓应用程序时,您需要为该应用程序生成一个唯一的数字签名,这个签名由一个公钥和一个私钥组成,公钥存储在应用程序中,私钥由开发者安全地保管,当...。
本站公告 2024-09-29 22:17:05
引言进度条是网站和应用程序中常见的元素,用于向用户显示任务或过程的完成进度,默认的进度条通常显得单调乏味,缺乏吸引力,通过自定义、样式和动画,我们可以解锁进度条的潜力,使之成为更加友好和引人入胜的交互元素,自定义进度条形状和大小进度条可以采用各种形状和大小,传统的水平或垂直条形最常见,但您还可以创建圆形、环形或其他自定义形状的进度条,...。
本站公告 2024-09-27 16:28:46
这是一款DiscuzX的插件,可以将附件存储到阿里云OSS,功能支持阿里云OSS附件存储支持附件上传、删除、下载支持附件缩略图生成支持自定义附件存储路径支持多附件同时上传支持附件分片上传支持附件断点续传安装下载插件解压插件将解压后的文件上传到论坛根目录进入论坛后台,点击插件管理,找到阿里云OSS附件插件,点击安装配置插件参数配置进入论...。
互联网资讯 2024-09-23 21:07:27
简介C语言是一种计算机编程语言,由丹尼斯·里奇在20世纪70年代开发,它是一种通用语言,可用于各种应用程序,从操作系统到嵌入式系统,C语言以其效率和可移植性而闻名,使其成为软件开发人员的热门选择,C语言基础数据类型C语言支持各种数据类型,包括整数、浮点数、字符和字符串,每个数据类型都有其自己的大小和存储规则,变量变量用于存储数据,在使...。
技术教程 2024-09-23 14:57:58
在Shell脚本中,变量是存储数据的基本单元,使用声明来明确变量的名称和类型,这有助于提高代码的可读性和可维护性,本指南将深入探讨Shell中变量声明的强大工具shelldeclare,什么是shelldeclare,shelldeclare是Bash和其他POSIX兼容Shell中的一个内置命令,用于声明和初始化变量,它提供了对变量...。
互联网资讯 2024-09-23 13:20:06
简介长整型,在许多编程语言中也称为整数,是一种用于存储整数的数据类型,它通常用于表示比标准整型更大的值,在某些情况下,使用长整型可以显著提高代码效率和性能,长整型的优点与标准整型相比,长整型具有以下优点,存储更大的值,长整型可以存储比标准整型更大的值,使其适用于需要处理大数的应用程序,减少溢出,由于长整型可以存储更大的值,它可以减少整...。
互联网资讯 2024-09-23 12:33:45
文本框是网站上常见的输入元素,它允许用户在其中输入文本,但有时当文本框中的内容较长或包含过多的行时,就会出现滚动条,默认情况下,文本框的滚动条样式可能不符合您网站的设计,因此自定义滚动条的外观有助于增强用户体验和网站的美观度,自定义滚动条样式要自定义滚动条样式,您可以使用CSS的,webkit,scrollbar伪类选择器,适用于...。
技术教程 2024-09-23 01:04:56
u003e以下是一个优雅下拉菜单的示例,下拉菜单选项1选项2选项3通过遵循这些技巧,您可以创建优雅且用户友好的下拉菜单,以增强您网站的交互体验,...。
互联网资讯 2024-09-13 20:03:34
=document.querySelector,function,.value,letresult,switch,functionName,casearcsin,result=Math.asin,angle,break,casearccos,result=Math.acos,angle,break,casearctan,resu...。
最新资讯 2024-09-13 14:21:51
简介Java虚拟机,JVM,是一个运行Java字节码的计算机程序,它负责加载、验证、执行和存储Java类文件,JVM是Java语言的基础,支持在各种平台上执行Java程序,JVM的体系结构JVM由以下主要组件组成,类加载器,负责加载Java类文件并将其转换为内部表示形式,字节码验证器,验证加载的类文件是否符合Java虚拟机规范,执行引...。
最新资讯 2024-09-12 22:49:46
前言中国作为全球数字化大国,对于开发者而言是一个充满机遇的沃土,为了助力中国开发者茁壮成长,本文汇集了丰富的资源和支持,旨在为他们的职业发展提供全方位的赋能,教育与培训在线课程平台网易云课堂,提供海量免费和付费课程,涵盖从基础编程到高级技术,Coursera,与世界名校合作,提供计算机科学、数据科学和AI等领域的认证课程,Udemy,...。
互联网资讯 2024-09-09 10:03:16
百邦手机快修连锁,1、口碑方面,百邦手机快修连锁在厦门非常的出名,是一家全国连锁店,具有非常好的口碑,2、技术方面,百邦手机快修连锁的技术非常不错,获得过,修手机的一些奖项,全国知名的手机连锁维修机构有哪些连锁手机维修店,其实不算多出名的也就那十来家,淘配配,闪修侠,极客修,加速度,e修大师,机大师,51修,Hi维修,爱维修,马上修,...。
技术教程 2024-09-02 04:02:24