线程同步
同步是多线程中的重要概念。同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果。同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字。
局部内部类中,若要引用从属的局部变量,那么这个变量必须是final的
1、同步方法
多个线程并发读写同一个临界资源时会发生“线程并发安全问题”
常见的临界资源
- 多线程共享实例变量
- 多线程共享静态公共变量
解决办法:
异步操作:多线程并发操作,相当于个干各的。
同步操作:有先后顺序的操作,相当于你干完我再干。
sychronized关键字
synchronized关键字是java中的同步锁。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。package com.xhj.thread;
/**
* 线程同步的运用
*
* @author XIEHEJUN
*
*/
public class SynchronizedThread {
class Bank {
private int account = 100;
public int getAccount() {
return account;
}
/**
* 用同步方法实现
*
* @param money
*/
public synchronized void save(int money) {
account += money;
}
/**
* 用同步代码块实现
*
* @param money
*/
public void save1(int money) {
synchronized (this) {
account += money;
}
}
}
这里写代码片
2、 即有synchronized关键字修饰的语句块。 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
代码如:
synchronized(object){
}
3、wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
package day04;
/**
* 线程同步
*
* @author Administrator
*
*/
public class ThreadDemo10 {
// 显示图片是否下载完毕
public static boolean isFinish;
public static Object obj = new Object();
public static void main(String[] args) {
// 下载线程
Thread download = new Thread() {
public void run() {
for (int i = 0; i <= 100; i++) {
System.out.println("down:图片下载" + i + "%");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
System.out.println("图片下载完成!");
isFinish = true;
/**
* 当图片下载完毕,就应当通知显示图片的线程 开始工作了
*/
synchronized (obj) {
obj.notify();
}
for (int i = 0; i <= 100; i++) {
System.out.println("down:附件下载" + i + "%");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
System.out.println("附件下载完成!");
isFinish = true;
}
};
/**
* main方法中定义一个内部类show, 该内部类中若想引用main方法中的其他 局部变量,那么这个变量必须是final的类型
*/
// 显示线程
Thread show = new Thread() {
public void run() {
try {
// 这里应该等待下载线程将图片加载完毕之后再执行
// download.join();
// 在obj上等待
synchronized (obj) {
obj.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i <= 100; i++) {
System.out.println("show:图片加载" + i + "%");
if (!isFinish) {
throw new RuntimeException("图片加载失败!");
}
}
System.out.println("图片显示完成!");
}
};
download.start();
show.start();
}
}
注意:
- 多线程看到的锁对象必须是同一个对象,否则没有效果。
- 如果sychronized块在某一个非静态方法中通常锁对象写的是this.
- notify:会随机解除一个在当前对象上等待的线程
- notifyAll:全部解除
- 调用哪个对象的wait或notify,就应当对当前的方法加锁,锁对象是当前对象。