1.4 线程的暂停
线程Thread类中的sleep方法能够暂停线程运行,单位为毫秒。Sleep方法可能会抛出InterruptedException异常。
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.print("Good!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
应用场景:
- 设计一定时间后关闭对话框
- 把按钮按下瞬间的状态显示给用户
在sleep方法中,停止时间也可以指定到纳秒(10^-9)单位。语法:Thread.sleep(毫秒,纳秒)。不过,通常Java平台运行无法实现这么准确的控制,具体精确程度依Java平台运行环境而不同。
1.5 线程的互斥处理
多线程中的各种程序都是自由运行的,所有它们有时会操作同一个实例,可能在某些情况下引发问题。
例如:从银行账户中取款时,余额确认部门的代码应该是下面这样。
if (可能余额大于等于取款金额){
从余额上减掉取款金额
}
但是,如果两个线程同时执行这段代码,那么可能余额会出现负数。
这种线程A和线程B之间竞争互相而引起的与预期相反的情况称为
数据竞争
或竞态条件
。这时候就需要一种“交通管制”来防止发生数据竞争,这种“交通管制”操作称为互斥
。Java使用关键字synchronized
来执行线程的互斥。
public class Bank {
private int money;
private String name;
public Bank(int money, String name) {
this.money = money;
this.name = name;
}
// 存款
public synchronized void deposit(int m) {
money += m;
}
// 取款
public synchronized boolean withdraw(int m) {
if (money >= m) {
money -= m;
return true
} else {
return false
}
}
public String getName() {
return name;
}
}
一个实例中的
synchronized
方法每次只能由一个线程运行。当正在使用synchronized
方法的线程运行完之后,便会释放锁。线程的互斥机制成为
监视
。获取锁有时也叫做“拥有监视”或“持有锁”。当前线程是否以获取某一个对象的锁可以通过Thread.holdsLock方法来确认。
synchronized代码块
如果只想让方法中的某一部分由一个线程运行,而非整个方法,则可以使用synchronized代码块。
synchronized (表达式){
...
}
其中“表达式”为获取锁的实例。synchronized代码块用于精确控制互斥处理的执行范围
。
synchronized 实例方法和 synchronized 代码块
synchronized void method(){
...
}
这跟下面的 synchronized 代码块包围起来的是等效的。
void method(){
synchronized (this){
...
}
}
synchronized实例方法是使用
this的锁
来执行线程的互斥处理。
synchronized 静态方法和 synchronized 代码块
synchronized静态方法每次只能由一个线程运行。但是synchronized静态方法使用的锁和synchronized实例方法使用的锁是不一样的。
class Something {
static synchronized void method (){
...
}
}
这跟下面的synchronized代码块包围起来的是等效的。
class Something {
static void method () {
synchronized (Something.clss){
...
}
}
}
synchronized 静态方法是使用该类的
类对象的锁
来执行线程互斥的。