JAVA线程及简单同步实现的原理解析html
摘要: JAVA线程及简单同步实现的原理解析线程1、内容简介: 本文主要讲述计算机中有关线程的相关内容,以及JAVA中关于线程的基础知识点,为之后的深刻学习作铺垫。若是你已是高手了,那么这篇文章并不适合你。java
线程
1、内容简介:
本文主要讲述计算机中有关线程的相关内容,以及JAVA中关于线程的基础知识点,为之后的深刻学习作铺垫。若是你已是高手了,那么这篇文章并不适合你。
2、随笔正文:
一、计算机系统组成
计算机系统由计算机硬件系统和软件系统组成。咱们今天要说的线程和硬件系统中的cpu中央处理器,及软件系统中的操做系统,进程等有比较紧密的联系。操做系统是软件中比较特殊的存在,与硬件系统直接交互,其余程序(软件)运行在操做系统之上。
二、cpu简单说明
硬件系统中特别重要的一项就是处理器CPU,与咱们所说的线程有很是紧密的联系。cpu中有几项参数,以及如何查看该信息,在下文逐一说明:
块数:民用pc机,基本都是一块物理cpu,每块主板上只能装一块cpu。
核心数:也就是单块物理cpu是由几组处理芯片组,组成的。4核心 8核心等。
线程数:老款cpu都是单线程的,及一组芯片组只能运行一个线程。现款因特尔cpu大多支持超线程技术可支持多个逻辑线程。可是须要操做系统及相关编程语言的支持,JAVA相较C++在多线程方面能表现的更出色。
主频:单位GHZ(hz赫兹 每秒的周期性变更重复次数)在计算机中即高低电平变化一次,能够产生两个不一样的电信号0、1。以个人CPU I5-4200M 2.5GHZ 举例,及cpu能够每秒完成25亿次震荡! 也就是说主频越高理论上计算能力越强,处理计算机指令越快。可是并不表明计算机总体运算速度约高,这点一般知足水桶效应,而cpu一直稳居长板地位。
缓存:cpu内置缓存,很小一般为几Mb至十几Mb,和cpu交互更频繁,速度也远高于普通运行内存,提升cpu处理能力的有效手段。
查看cpu参数指令:
DOS命令chrome
三、关系梳理
操做系统,程序,进程,线程之间的关系梳理、
程序:是计算机上的静态代码,指令文件集合,是静态的存在。好比:QQ,LOL等
进程:程序的执行实体(过程),持有及分配资源的主体。chrome.ext,QQ.exe等执行进程。
线程:是进程中的劳动力,由进程建立,完成指定任务后结束。
关系:
操做系统 1 ——> n 程序 1 ——> n 进程 1 ——> n 线程
平台 集合 资源 干活的
普通进程建立线程去完成指定的计算机指令,这个时候须要调用系统资源如cpu进行运算,可是用户线程并不能直接驱动硬件,而是经过操做系统去统一分配、控制硬件的使用。编程
四、进程、线程基本状态
五个基本状态,建立和终止不说了。计算机中的线程建立以后会进入就绪状态,当cpu为此线程分配时间片时,线程由就绪转为执行状态,开始干活,当时间片结束时回到就绪状态等待下次获取时间片,循环直到任务完成,当任务完成时,线程终止(死亡)。若在执行过程当中遇到耗时操做好比IO或者JAVA中的线程休眠等,会进入阻塞状态,阻塞结束会进入就绪状态继续排队等待被分配时间片。缓存
五、JAVA中的线程
java中提供了两种方式去建立线程,继承类和实现接口。因为java中单继承机制的限制,大多数状况下使用实现Runnable接口的形式建立线程。
1 、继承Thread类
继承Thread类
二、实现Runnable接口
实现Runnable接口
三、线程的经常使用方法网络
1 start()
2 //启动线程,调用run方法
3 sleep()
4 //线程休眠,进入阻塞状态,让出时间片,但不会让出锁
5 Thread.currentThread()
6 //获取当前执行线程
7 wait/notify()
8 //仅能存在synchronized代码块中,wait线程休息,让出时间片,进入等待状态,notify()唤醒该线程;该方法存在重载
9 join()
10 //等待此线程执行完毕
11 setDaemon()
12 //设置守护线程,守护线程是服务线程,当用户线程结束,守护线程自动结束
13 yield()
14 //主动让出时间片给其余线程
15 interrupt()
16 //中断线程,不推荐
17 get/setId()
18 //设置获取线程id
19 get/setName()
20 //设置获取线程名
21 get/setPriority()
22 //设置获取线程优先级,理论上优先级越高,获取时间片的几率越大,默认是5最高10最小1
复制代码
四、JAVA中的线程状态图
五、线程练习
简单模拟多线程购票业务
售票业务
在不作任何控制的状况下,出错的概率很小,我反复测试几回,结果基本都正确!分析缘由:业务自己相对简单,没有耗时操做,每一个时间片基本能保证线程将本次任务执行完毕!也就是将票数减一并打印内容。
为了模拟在售票前双方的问询阶段及付款阶段的等待,在售票前(后)加入Thread.sleep(ms) 模拟耗时操做。
加入线程休眠
改动后系统出现bug同一张票被售出了屡次,而且可能将票卖出负数。究其缘由:线程之间的数据争用问题,咱们将引入JAVA内存模型进行分析(图片来自网络侵删)
首先咱们须要知道几个概念,以下:
共享变量:主内存中存在被多个线程同时用到的变量,在多个线程中存在相应副本变量。
可见性:线程对共享变量的值进行修改,可否被其余线程可见。
变量访问规则: 一、线程对共享变量的操做只能在本身工做内存中的副本。
二、工做内存中的变量变化须要经过主内存传递。
六、实现同步
实现同步即实现共享变量可见性,工做内存1 ——> 主内存 ——>工做内存2,在数据传递的两个环节中出现问题都会对同步形成影响,从而影响执行结果。
synchronized实现同步
synchronized 能够实现指令的原子性,及共享变量的可见性。
原子性:synchronize修饰的方法或者代码块会获取互斥锁,保证同一时间只能有一个对象访问该方法或代码块,将其做为一个总体,保证了原子性。
可见性:加锁后,先清空工做内存,同步主内存中的共享变量。解锁前,先将工做内存中的变量同步到主内存,再释放锁。
因此结合上述例子,为sellTickets()方法加锁便可实现同步;或者对核心代码片断加锁;
复制代码
private synchronized boolean sellTickets() { //… 省略中间代码
}
//或者以下实现
synchronized(this){
[Java] 纯文本查看 复制代码
?
1
//this指的是调用sellTickets()的对象
}多线程
七、volatile关键字
共享变量(类的成员变量、类的静态成员变量)被volatile修饰以后,那么就具有了两层语义:
原理:被volatile修饰的变量所生成汇编代码时有lock前缀,生成"内存屏障"。
1)保证了不一样线程对这个变量进行操做时的可见性,即工做内存中的变量值在修改后会被当即同步到主内存中;
2)而且使其余线程中的缓存无效,这样当其余线程在访问共享变量时就必须取主内存中获取;
3)禁止进行指令重排序;
综上所述,volatile能够保证可见性,但不能保证原子性;
举例分析:编程语言
volatile int number = 0 ;
number ++ ;
/*
[Java] 纯文本查看 复制代码
?学习
操做能够解析成三步: 1.获取number中的值测试
2.计算加1操做 3.number = 0 + 1;
在一个时间片中,虽然volatile修饰的number必定会被当即同步到主内存中,但不能保证完整执行这三步,因此不能保证++操做的原子性 。
原文地址https://www.cnblogs.com/lijiz...