黑马程序员技术交流社区
标题:
线程同步的N种方法,总有一个适合你
[打印本页]
作者:
上篮高手
时间:
2013-10-19 11:04
标题:
线程同步的N种方法,总有一个适合你
本帖最后由 上篮高手 于 2013-10-19 12:01 编辑
1: 最简单也是最常用的: 使用方法实现线程同步
所谓同步方法,即有Syschronized 关键字修饰的方法。其原理是通过java的内置锁实现的,其实每个
java 对象都有一个内置锁,如果方法用此关键字声明了,该内置锁会保护整个方法。
例子如下:
这是一个银行类: 负责往里头存钱 ,和 查询当前存款。
private class Bank {
private int account = 100;// 每个账户的初始金额是100元
public synchronized void deposit(int money) {// 向账户中存入money元
account += money;
}
public int getAccount() {// 查询账户余额
return account;
}
}
复制代码
这是个继承Runnable 的Trannsfer类: 这是一个带传入参数的
private class Transfer implements Runnable {
private Bank bank;
private JTextArea textArea;
public Transfer(Bank bank, JTextArea textArea) {// 初始化变量
this.bank = bank;
this.textArea = textArea;
}
public void run() {
for (int i = 0; i < 10; i++)
复制代码
这是线程的运行如下:
Bank bank = new Bank();
Thread thread1 = new Thread(new Transfer(bank, thread1TextArea));
thread1.start();
Thread thread2 = new Thread(new Transfer(bank, thread2TextArea));
thread2.start()
复制代码
打印结果如下:
一线程:
账户的余额是:110
账户的余额是:130
账户的余额是:160
账户的余额是:180
账户的余额是:200
账户的余额是:210
账户的余额是:230
账户的余额是:260
账户的余额是:280
账户的余额是:300
二线程:
账户的余额是:120
账户的余额是:140
账户的余额是:150
账户的余额是:170
账户的余额是:190
账户的余额是:220
账户的余额是:240
账户的余额是:260
账户的余额是:270
账户的余额是:290
2: 使用代码块实现线程的同步:
Syschonized 不仅可以修饰方法,还可以修饰代码块。
格式为: syschronized(objcect) {}
还是刚才的例子:修改如下:
private class Bank {
private int account = 100;
public void deposit(int money) {
synchronized (this) {// 获得Bank类的锁 *******注意了
account += money;
}
}
public int getAccount() {
return account;
}
}
复制代码
3: 使用特殊变量实现线程同步:
volatile 关键字为域变量提供了一种免锁机制。使用这个关键字相当于告诉虚拟机该变量可能会被其他线程修改,因此每次使用该变量时就要
更新计算,而不是使用寄存器里头的值。它不能用来修饰final 类型的变量。
还是刚才的例子:
private class Bank {
private volatile int account = 100;// 将域变量用volatile修饰 *******注意了
public void deposit(int money) {// 向账户中存钱
account += money;
}
public int getAccount() {// 获得账户余额
return account;
}
}
复制代码
4: 使用重入锁实现线程的同步:
java se 5.0 增加了一个java.util.comcurrent 包来支持同步。
ReentrantLock类是可重入 互斥 实现了Lock接口的锁。
方法有:
ReentrantLock() 无参构造函数,创建一个实例
lock() 获得锁
unlock() 释放锁。
应用如下:
private class Bank {
private int account = 100;// 账户的初始金额是100
private Lock lock = new ReentrantLock();// 创建重入锁对象 **********注意了
public void deposit(int money) {
lock.lock();// 打开锁
try {
account += money;
} finally {
lock.unlock();// 关闭锁
}
}
public int getAccount() {// 查看余额
return account;
}
}
复制代码
5: 使用线程局部变量实现线程同步:
类: ThreadLocal 来管理变量,则每个使用该变量的线程都会获得该变量的副本,副本之间相互独立,这样每个线程都
可以随意修改自己的副本,而不会对其他线程产生影响。
方法如下:
ThreadLocal () 无参构造函数
get() 返回当前线程副本中的值
initialValue() 返回当前线程的初始值。
set(T value) 设置副本中的值。
应用如下:
发现
account变量用
new ThreadLocal<Integer>() 来创建了
public class Bank {
// 使用ThreadLocal类来管理共享变量account
private static ThreadLocal<Integer> account = new ThreadLocal<Integer>() { //*******注意
@Override
protected Integer initialValue() {
return 100;// 重写initialValue()方法,将account的初始值设为100
}
};
public void deposit(int money) {
account.set(account.get() + money);// 利用account的get()、set()方法实现存钱 //*******注意
}
public int getAccount() {// 获得账户余额
return account.get(); //*******注意
}
}
复制代码
总结: 以上5中方法实现同步,大家可以任选自己喜欢的方法。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2