线程基础:线程(2)——JAVA中的基本线程操作(上)
来源:互联网 发布:linux集成开发环境 编辑:程序博客网 时间:2024/05/21 06:53
1、JAVA中线程的状态
1-1、#对象锁
在Java中每一个对象都有一把‘锁’,这个‘锁’可以是开放状态;也可以由某一个线程(或者多个线程)持有‘钥匙’;一旦在系统中某个对象的‘锁’存在至少一把‘钥匙’,那么任何线程操作这个对象,都必须验证是否有‘钥匙’,如果没有则会报IllegalMonitorStateException异常。
可是‘锁芯’(对象独占权)只有一个,那么可以打开这把锁的多个‘钥匙’同一时间内只能有一把‘钥匙’进行操作;其他持有‘钥匙’的线程(或者没有持有钥匙的线程)都要进入等待状态;直到某把‘钥匙’从‘锁眼’中退出,操作系统会决定哪一把‘钥匙’重新插入‘锁芯’(操作系统线程切换)。
某一个线程在执行过程中,可以随时为任何一个对象‘加锁’;也可以随时归还这个对象锁的‘钥匙’。如果归还了这个对象锁的‘钥匙’,那么这个线程(在对象加了锁的状态下)肯定就不再具有这个对象的操作权了。
需要注意:某一个线程拥有一个对象的‘锁’的‘钥匙’,并不代表这个线程的‘钥匙’是插入了‘锁芯’的(有这个对象的控制权);但是,有权抢占‘锁芯’控制权的线程,必定拥有这个对象的‘钥匙’。
线程中,‘锁芯’代表对象的独占控制权;需要对某个对象的锁状态进行检测的关键字为‘synchronized’(临界区)。能将钥匙拔出锁芯,但是又不归还锁的调用方法(释放对象独占状态,并能在后续参与对象独占竞争的方法),只有wait和wait(time)。归还钥匙的方式包括:线程中针对某个对象的临界区正常完成、有异常抛出到临界区外(临界区异常完成)
请一定注意wait(time)的用法。很多初学者(包括我本人在很长一段时间)的理解都是:‘等待一段时间time,然后该线程激活继续工作’;但是如果您按照上文的描述,就会发现这样的理解是有问题的。实际上time更准确的含义应该是:到时检查。而整个wait(time)更准确的理解应该是:释放这个线程独占的X对象的锁芯(独占权),以便其它可以抢占‘锁芯’(独占权)的线程能够进行抢占,但是本线程继续持有X对象的锁的钥匙,等待time的时间后,重新参与‘锁芯’抢占(不一定能够抢占得到)。
1-2、对象锁的工作过程
下图表示了线程中,对象锁的工作过程:
我们以一个实际代码例子来看看所描述的锁的工作过程:
package test.thread.lock;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class ThreadLock { /** * 拿来加锁的对象 */ private static final Object WAIT_OBJECT = new Object(); /** * 日志,如果您没有log4j,请使用System.out */ private static final Log LOGGER = LogFactory.getLog(ThreadLock.class); /** * 偷懒,我把异常全部抛出了。正式系统不要这么搞哦!! * @param args * @throws Exception */ public static void main(String[] args) throws Exception { Thread threadA = new Thread(new Runnable() { @Override public void run() { // 检查'对象锁'状态。 synchronized (ThreadLock.WAIT_OBJECT) { ThreadLock.LOGGER.info("做了一些事情。。。。"); } } }); Thread threadB = new Thread(new Runnable() { @Override public void run() { // 检查'对象锁'状态。 synchronized (ThreadLock.WAIT_OBJECT) { ThreadLock.LOGGER.info("做了另一些事情。。。。"); } } }); threadA.start(); threadB.start(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
代码很简单,应该不需要做过多说明吧:创建了两个线程threadA和threadB。两个线程的执行方法中都需要对ThreadLock.WAIT_OBJECT这个Object进行对象锁状态检查。下面我们通过eclipse的调试状态看看线程的执行过程:
threadA和threadB开始工作了。请注意,这是两个线程都没有持有任何对象锁的钥匙:
ThreadA开始进行ThreadLock.WAIT_OBJECT对象锁检查,发现没有任何线程占有这个对象锁的锁芯。于是JVM为这个线程创建一把对象锁的钥匙,并让这个线程的钥匙占据锁芯(独占这个对象的操作权):
这时ThreadB也开始进行ThreadLock.WAIT_OBJECT对象锁检查,但是发现ThreadLock.WAIT_OBJECT对象锁的锁芯已经被某个线程占据(ThreadA正在独占),于是停留在检查位等待:
ThreadA继续运行,直到synchronized关键字标示的临界区全部执行完毕,于是释放锁芯,归还锁。ThreadB发现ThreadLock.WAIT_OBJECT不再处于独占状态(锁芯没有任何钥匙插在哪里),于是解除等待状态,获得ThreadLock.WAIT_OBJECT的对象锁钥匙,插入锁芯,继续执行:
1-3、synchronized可标注的位置
在JAVA中synchronized关键字可以加载很多位置。您可以在一个方法定义上加synchronized关键字、也可以在方法体中加synchronized关键字、还可以在static块中加synchronized关键字。如下的代码都是正确的:
// 代码片段1static { synchronized(ThreadLock.class) { }}// 代码片段2public synchronized void someMethod() {}// 代码片段3public synchronized static void someMethod() {}// 代码片段4public static void someMethod() { synchronized (ThreadLock.class) { }}// 代码片段5public void someMethod() { synchronized (ThreadLock.class) { }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
但是不同位置的synchronized的关键字,代表的含义是不一样的。synchronized(){}这个写法,开发人员可以指定需要检查的对象锁。但是当synchronized加载在方法上时,有的读者就感觉有点混淆了。这里详细说明一下:
synchronized关键字加载在非静态方法上时:
其代表的含义和synchronized(this){}的意义相同。即对所拥有这个方法的对象进行对象锁状态检查。synchronized关键字加载在静态方法上时:
其代表的含义和synchronized(Class.class)的意义相类似。即对所拥有这个方法的类的对象进行对象锁状态检查(类本身也是一个对象哦 ^_^)。
(接下文)
- 线程基础:线程(2)——JAVA中的基本线程操作(上)
- 线程基础:线程(2)——JAVA中的基本线程操作(上)
- 线程基础:线程(3)——JAVA中的基本线程操作(中)
- 线程基础:线程(4)——JAVA中的基本线程操作(下)
- 线程基础:线程(3)——JAVA中的基本线程操作(中)
- 线程基础:线程(4)——JAVA中的基本线程操作(下)
- 线程(2)——JAVA中的基本线程操作(上)
- 线程(3)——JAVA中的基本线程操作(中)
- 线程(4)——JAVA中的基本线程操作(下)
- 线程基础:线程池(5)——基本使用(上)
- 线程基础:线程池(5)——基本使用(上)
- 线程基础:线程池——基本使用(下)
- Java中的多线程(一)关于线程的基本操作
- 有关Java中的线程、有关Android中的线程(上)
- java线程(5)——线程池(上)
- 线程篇(一):Java中的线程(基础)
- Java基础—线程
- Java中的线程基础
- Java 数组初始化的两种方法
- 软连接建立出错 Operation not supported
- (一) Linux Centos7下SVN服务器搭建详细教程
- java的内存模型
- loadrunner动态从mysql取值 [需要下载跟数据库服务器一致的dll,32位或64位]
- 线程基础:线程(2)——JAVA中的基本线程操作(上)
- [学习笔记]设计模式[2]-{装饰者模式}
- NHibernate之旅(10):探索父子(一对多)关联查询
- Apache OpenNLP下载
- 比好看的一些自定义SeekBar
- 什么是Docker
- Windows 10四大版本官方对比:国人肯定专业版
- 获取系统/sdcard存储空间路径无效的处理
- 同步/异步 与 阻塞/非阻塞的区别