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

来源:互联网 发布:软件过了试用期 编辑:程序博客网 时间:2024/05/22 10:33
【条件竞争:    在多线程的开发中,两个及其以上的线程需要共享统一数据的存取。如果两个线程存取相同的对象,并且每一个线程都调用一个修改该对象状态的方法,    根据线程访问数据的顺序,可能会出现错误的数据结果,这种现象成为条件竞争。因为修改对象状态的方法并不是一个原子操作,通常步骤是:    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());    }}

原创粉丝点击