您的位置:首页 > 编程语言 > Java开发

java并发系列——基本线程同步(一)

2015-12-31 00:03 399 查看

一、介绍

在并发编程中常见的多个线程共享同一资源,比如多个线程读或些相同的数据库,或访问同一个文件等,这些共享资源在多线程操作下会引起数据不安全问题,本章介绍一些机制来避免此问题。

java提供了同步机制来实现一个临界区,当一个线程想要访问一个临界区,它使用其中的一个同步机制来找出是否有任何其他线程执行临界 区。如果没有,这个线程就进入临界区。否则,这个线程通过同步机制暂停直到另一个线程执行完临界区。当多个线程正在等待一个线程完成执行的一个临界 区,JVM选择其中一个线程执行,其余的线程会等待直到轮到它们。

二、同步方法

(1)、同步的概念

Java中如何使用一个最基本的同步方法,即使用 synchronized关键字来控制并发访问方法。只有一个执行线程将会访问一个对象中被synchronized关键字声明的方法。如果另一个线程试图访问同一个对象中任何被synchronized关键字声明的方法,它将被暂停,直到第一个线程结束方法的执行。

换句话说,每个方法声明为synchronized关键字是一个临界区,Java只允许一个对象执行其中的一个临界区。

(2)、实例说明

下面介绍一个银行取款和存款的例子来说明多个线程访问共同对象,在没有同步的方法下,会引起账户结果不正确。

1.Account类

public class Account {
private double balance;
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}

//增加balance的值的方法
public synchronized void addAmount(double amount){
double tmp=balance;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tmp+=amount;
balance=tmp;
}

//减少balance的值的方法
public synchronized void subAmount(double amount){
double tmp=balance;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tmp-=amount;
balance=tmp;
}
}


2.Bank类模拟ATM取款

public class Bank implements Runnable {
public Account account;
public Bank(Account account){
this.account=account;
}
@Override
public void run() {
for(int i=0;i<100;i++){
account.subAmount(100);
}
}
}


3.Company类模拟存款

public class Company implements Runnable {
public Account account;
public Company(Account account){
this.account=account;
}
@Override
public void run() {
for(int i=0;i<100;i++){
account.addAmount(100);
}
}
}


(3)、synchronized的其他特性

synchronized关键字不利于应用程序的性能,所以你必须仅在修改共享数据的并发环境下的方法上使用它。如果你有多个线程正在调用一个synchronized方法,在同一时刻只有一个线程执行它,而其他的线程将会等 待。如果这个操作没有使用synchronized关键字,所有线程可以在同一时刻执行这个操作,减少总的执行时间。如果你知道一个方法将不会被多个线程 调用,请不要使用synchronized关键字

(4)synchronized保护代码块

synchronized关键字以这样的方式来保护访问的共享数据,其余的操作留出此代码块,这将会获得更好的应用程序性能。这个目标就是让临界区(在同 一时刻可以被多个线程访问的代码块)尽可能短。我们已经使用了synchronized关键字来保护访问指令,将不使用共享数据的长操作留出此代码块。当 你以这个方式使用synchronized关键字,你必须通过一个对象引用作为参数。只有一个线程可以访问那个对象的synchronized代码(代码 块或方法)。

通常,我们将使用this关键字引用执行该方法的对象。

synchronized (this) {

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: