第一种:同步代码块
同步代码块的核心是设置同步监视器,原则上在Java中可以设置任何对象为同步监视器,但通常设置可能并发访问的共享资源对象为同步监视器。语法格式如下:
synchronized(obj) {
……
}
示例代码,模拟多个用户对同一个账户的取钱操作:
1: //当多条线程修改同一共享数据时, 将涉及到线程安全
2: public void run() {
3: synchronized(account) {
4: //账户余额大于期望取到的金额
5: if (account.getBalance() >= drawAmount) {
6: //吐抄
7: System.out.println(getName() + "取钱成功,突出钞票:" + drawAmount);
8:
9: //修改余额
10: account.setBalance(account.getBalance() - drawAmount);
11: System.out.println("\t余额为:" + account.getBalance());
12: }
13: else {
14: System.out.println("余额不足,取钱失败!");
15: }
16: }
17:
18: }
第二种:同步方法
同步方法可以看作是同步代码块的变体,他不需要显示指定同步监视器,不过实则是把自己this当作同步监视器,因此而知同步方法是定义在要操作类的内部。示例代码,同样模拟取钱操作:
1: package org.frzh.thread;
2:
3: public class Account2 {
4: private String accountNo;
5: private double balance;
6:
7: public Account2() {}
8: public Account2(String accountNo, double balance) {
9: this.accountNo = accountNo;
10: this.balance = balance;
11: }
12:
13: public double getBalance() {
14: return this.balance;
15: }
16: //线程安全方法
17: public synchronized void draw(double drawAmount) {
18: //账户余额大于期望取到的金额
19: if (this.balance >= drawAmount) {
20: //吐抄
21: System.out.println(Thread.currentThread().getName() + "取钱成功,突出钞票:" + drawAmount);
22:
23: //修改余额
24: this.balance -= drawAmount;
25: System.out.println("\t余额为:" + this.balance);
26: }
27: else {
28: System.out.println("余额不足,取钱失败!");
29: }
30: }
31: }
同步方法和同步代码库比较而言,同步方法更符合面向对象编程的思想。
第三种:同步锁(Lock)
同步锁是在线程访问共享资源时将资源锁定,此时不允许其他线程对共享资源的访问,操作完成之后再释放同步锁(且必须显示调用)。相比较同步代码块和同步方法而言,同步锁显得更加灵活,当然使用起来也是最容易出粗的。示例代码:
1: package org.frzh.thread;
2:
3: import java.util.concurrent.locks.ReentrantLock;
4:
5: public class Account3 {
6: //定义所对象
7: private final ReentrantLock lock = new ReentrantLock(); //可重入锁
8: private String accountNo;
9: private double balance;
10:
11: public Account3() {}
12: public Account3(String accountNo, double balance) {
13: this.accountNo = accountNo;
14: this.balance = balance;
15: }
16:
17: public double getBalance() {
18: return this.balance;
19: }
20:
21: public void draw(double drawAmount) {
22: lock.lock();
23: try {
24: //账户余额大于期望取到的金额
25: if (this.balance >= drawAmount) {
26: //吐抄
27: System.out.println(Thread.currentThread().getName() + "取钱成功,突出钞票:" + drawAmount);
28:
29: //修改余额
30: this.balance -= drawAmount;
31: System.out.println("\t余额为:" + this.balance);
32: }
33: else {
34: System.out.println("余额不足,取钱失败!");
35: }
36: } finally {
37: lock.unlock();
38: }
39: }
40: }