java并发编程学习6--同步--synchronized关键字

【条件竞争:
    在多线程的开发中,两个及其以上的线程需要共享统一数据的存取。如果两个线程存取相同的对象,并且每一个线程都调用一个修改该对象状态的方法,
    根据线程访问数据的顺序,可能会出现错误的数据结果,这种现象成为条件竞争。因为修改对象状态的方法并不是一个原子操作,通常步骤是:
    1.读取当前状态值到线程工作内存。
    2.在线程工作内存中修改状态值。
    3.将修改后的状态值重新写入主内存。
    而问题往往就是有多个线程同时在执行步骤2。

【措施:
    有两种机制代码受并发访问的干扰:
    1.synchronized关键字。
    2.Reentrantlock类。

【synchronized关键字:
    java中每个对象都有一个内部锁。如果一个方法是用synchronized关键字修声明的,那么对象的锁将保护整个方法,也就是说要调用该方法,线程必须获得
    对象内部锁。内部锁有如下的特点:
    1.不能中断正在试图获得锁的线程。
    2.试图获得锁不能设置超时时间。
    3.只有一个条件:要么获得,要么等待,没有粒度更细的控制。

【例子:
    下面的代码表示多个线程修改同一个对象造成数据失误的情况:
public class Sync {

    private int value;

    void add(){
        this.value ++;
    }
    int getValue(){
        return this.value;
    }

    public static void main(String[] args) {
        for (int i = 0; i <30 ; i++) {
            Sync s = new Sync();
            List<CompletableFuture> cfs = new ArrayList<>();
            cfs.add(CompletableFuture.runAsync(() -> s.add()));
            cfs.add(CompletableFuture.runAsync(() -> s.add()));
            cfs.add(CompletableFuture.runAsync(() -> s.add()));
            //等待子线程执行完毕
            CompletableFuture.allOf(cfs.toArray(new CompletableFuture[cfs.size()])).join();
            System.out.println(s.getValue());
        }
    }
}

    现在使用synchronized关键字修饰add()看看:

数据正常。
【注意:

    如果我们在同步的时候需要判断,切记将条件判断放在同步代码块之中,如果在外部判断,很有可能出现:
	1.第一个线程通过条件判断
	2.第二个线程获得cpu,并修改了共享对象
	3.第一个线程再次获得cpu此时已经不满足条件,但是代码在向下执行,于是出现异常的情况。
例如转账的例子:
public class Account {
    //账户金额
    private int amount;

    public Account(int amount){
        this.amount = amount;
    }

    //转账
    public synchronized void trans(Account to,int value){
        //条件判断处于同步代码中!!!!!!
	if(amount - value < 0){
            throw new RuntimeException("钱不够了!");
        }
        this.amount -= value;
        to.addAmount(value);
        System.out.println("转账成功");
    }

    public void addAmount(int amount){
        this.amount += amount;
    }
    public int getAmount(){
        return this.amount;
    }

    public static void main(String[] args) {
        Account from = new Account(100);
        Account to1 = new Account(0);
        Account to2 = new Account(0);
        List<CompletableFuture> cfs = new ArrayList<>();
        cfs.add(CompletableFuture.runAsync(() -> from.trans(to1,100)));
        cfs.add(CompletableFuture.runAsync(() -> from.trans(to2,100)));
        CompletableFuture.allOf(cfs.toArray(new CompletableFuture[cfs.size()])).join();
        System.out.println(from.getAmount());
        System.out.println(to1.getAmount());
        System.out.println(to2.getAmount());
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值