java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaEE, JavaME, JavaSE)的总称。本站提供基于Java框架struts,spring,hibernate等的桌面应用、web交互及移动终端的开发技巧与资料
保持永久学习的心态,将成就一个优秀的你,来 继续搞起java知识。
| 类别 | 方法 | 简介 |
| 线程的创建 | Thread() | |
| Thread(String name) | ||
| Thread(Runable target) | ||
| Thread(Runable target,String name) | ||
| 线程的方法 | void start() | 启动线程 |
| static void sleep(long millis) | 线程休眠 | |
| static void sleep(long millis,int nanos) | ||
| void join() | 使其他线程等待当前线程终止 | |
| void join(long millis) | ||
| void join(long millis,int nanos) | ||
| static void yield() | 当前运行线程释放处理器资源 | |
| 获取线程的引用 | static Thread currentThread() | 返回当前运行的线程引用 |
1.中断线程
当线程的run方法执行方法体中最后一条语句后,并经由执行return语句返回时,或者出现了在方法中没有捕获的异常时,线程将终止。
1.1 错误方法stop
在Java的早起版本中,有一个stop方法,其他线程可以调用它终止线程。但是这个方法已经被弃用了。
1.2 interrupt方法
interrupt方法可以被用来请求终止线程。当对一个线程调用interrupt方法时,线程的中断状态将被置位。这是每一个线程都具有的boolean标志。每个线程都应该不时的检查这个标志,以判断线程是否被中断。
要想弄清楚中断状态是否被置位
(1)对于用Runable接口实现的线程来说首先调用静态的Thread.currentThread方法获得当前线程,然后调用isInterrupted方法:
1(2)对于用Thread类实现线程来说直接调用isInterrupted方法:
1如果线程被阻塞,就无法检测中断状态。这是产生InterruptedException异常的地方。当在一个被阻塞的线程(调用sleep或wait)上调用interrupt方法时,阻塞调用将会被InterruptedException异常中断。
案例一:
11运行结果:
1从上面的结果来看interrupted方法并没有使线程中断。
案例二:
1运行结果:
1从上面的运行结果来看interrupted方法使线程中断,其实质是当对一个线程调用interrupt方法时,线程的中断状态将被置位。这是每一个线程都具有的boolean标志。每个线程都应该不时的检查这个标志,以判断线程是否被中断。但是确保线程不被阻塞,否则中断状态检测不出。这就是上面为什么使用
while(System.currentTimeMillis()-
time <1000){}
而不是sleep(1000)的原因
案例三:
1运行结果:
1如果中断状态置位时,调用sleep方法,它不会休眠。相反,它将清除这一状态(从结果中看出线程没有终止,一直运行)并且抛出InterruptedException异常。因此你的while循环调用sleep
函数,不会检测中断状态。相反,要如下所示捕获InterruptedException异常。
1注释:
| void interrupt() 向线程发送中断请求。线程的中断状态将被设置为true。
如果目前该线程被一个sleep(long),sleep(long,int),join(),join(long),join(long,int),wait(),wait(long), wait(long,int)调 用阻塞,那么,中断状态将被清空,同时InterruptedException异常被抛出。 static boolean interrupted() 测试当前线程(即正在执行这一命令的线程)是否被中断。 注意:这是一个静态方法。这一调用会产生副作用-它将当前线程的中断状态重置为false。 boolean isInterrupted() 测试线程是否被终止。不像静态的中断方法,这一调用不用改变线程的中断状态。 |
2.线程同步
如果两个线程存取相同的对象,并且每一个线程都掉用了一个修改该对象状态的方法,将会发生什么?可以想象,线程彼此踩了对方的脚。
这样的一种情况通常称为竞争条件。
2.1 竞争条件的一个例子
为了避免多线程引起的共享数据的混乱,必须学会如何同步存取。
下面的测试程序中,模拟一个有若干账户的银行。随机的生成这些账户之间转移钱的交易。每一个账户有一个线程,每一笔交易中,会从线程服务的账户中随机转移一笔钱款到另一个账户中。
2.2 竞争条件详解
当两个线程试图同时更新同一个帐号的时候,这个问题就出现了。假定两个线程同时执行指令:
1假定第一个线程调用transfer,在执行结束前被剥夺了运行权。假定第二个线程也调用transfer,由于第二个线程不能获得锁,将在调用lock方法时被阻塞。它必须等待第一个线程完成transfer方法的执行之后才能再度被激活。当第一个线程释放锁时,第二个线程才能开始运行。
注意:
| 每一个Bank对象有自己的ReentrantLock对象。如果两个线程试图访问同一个Bank对象,那么锁以串行方式提供服务。
如果两个线程访问不同的Bank对象,每一个线程得到不同的锁对象,两个线程都不会发生阻塞。 要留心临界区中代码,不要因为异常的抛出而跳出了临界区。如果在临界区代码结束之前抛出了异常,finally子句释放锁,但会使对象处于一种受损的状态。 |
锁是可重入的,因为线程是可以重复的获得已经持有的锁。锁保持一个持有计数来跟踪对lock方法的嵌套调用。线程在每一次调用lock都要调用unlock来释放锁。由于这一特性,被一个锁保护的代码可以调用另一个使用相同的锁的方法。
例如,transfer方法调用GetTotalBalance方法,这也会封锁banklock对象,此时banklock对象的持有计数为2。当GetTotalBalance方法退出的时候,持有计数变回1。当transfer方法退出时,持有计数变为0。线程释放。
因为水平有限,难免有疏忽或者不准确的地方,希望大家能够直接指出来,我会及时改正。一切为了知识的分享。
后续会有更多的精彩的内容分享给大家。
支付宝扫一扫
微信扫一扫
