以下为我阅读《Java语言程序设计》进阶篇的读书笔记,用以个人巩固复习。
/*程序1.1*/
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AccountWithoutSync {
private static Account account = new Account();
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
for(int i = 0;i<100;i++) {
executor.execute(new AddAPennyTask());
}
executor.shutdown();
while(!executor.isTerminated()) {}
System.out.println("balance:"+account.getBalance());
}
//an static inner class for thread
private static class AddAPennyTask implements Runnable {
public void run() {
account.deposit(1);
}
}
// an static inner class for account
private static class Account {
private int balance = 0;
public int getBalance() {
return balance;
}
public void deposit(int amount) {
int newBalance = balance + amount;
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
balance = newBalance;
}
}
}
在多线程中多个任务会一种引起冲突的方式访问一个公共资源,这是多线程中一个普遍的问题,称为资源冲突(race condition) 如果一个类的对象在多线程程序中没有引起资源冲突,则称这样的类位线程安全的(thread-safe)。
这个例子不是线程安全的。
为避免资源冲突,应该防止多个线程进入程序的某一特定部分,程序中这样的部分称为临界区(critical region)。上面程序的临界区是整个deposit方法。可以使用synchronized来同步方法,以便一次只有一个线程可以访问该方法,这样可以使Account类成为线程安全的,如下:
private **synchronized** static class Account (int amount);
随着deposit方法被同步化,如果任务1进入deposit方法,如果任务2已经在方法中,任务2就会被阻塞,直到任务1完成该方法的允许。
假设不允许修改Account类,可以添加一个新的同步方法,用这个方法调用deposit(1),并从run()中调用这个新方法。