synchronize关键字互斥

来源:互联网 发布:mac book pro 2015 编辑:程序博客网 时间:2024/06/07 20:22

当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁。获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁。这也意味着任何其他线程都不能进入该对象上的synchronized方法或代码块,直到该锁被释放

这样讲有点抽象看下面的这个例子

首先定义两个类,一个是House,House中bathroom和kitchen都是竞争的资源

class House {    private String bathRoom = "bathroom";    private String kitChen = "kitchen";    //静态同步方法修房子    public synchronized  static void repair(String username){        System.out.println(username + " is repairing " );        try {            TimeUnit.SECONDS.sleep(5);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(username + " finish repairing ");    }    //使用同步方法使用厨房    public synchronized void useKitChen1(String username) {        System.out.println(username + " is using " + kitChen);        try {            TimeUnit.SECONDS.sleep(5);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(username + " finish using " + kitChen);    }    //使用同步块使用厨房    public void useKitchen2(String username) {        synchronized (kitChen) {            System.out.println(username + " is using " + kitChen);            try {                TimeUnit.SECONDS.sleep(5);                int i = 45 + 5;            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(username + " finish using " + kitChen);        }    }    //使用同步方法使用浴室    public synchronized void useBathRoom1(String username) {        System.out.println(username + " is using " + bathRoom);        try {            TimeUnit.SECONDS.sleep(5);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(username + " finish using " + bathRoom);    }    //使用同步快使用浴室    public void useBathRoom2(String username) {        synchronized (bathRoom) {            System.out.println(username + " is using " + bathRoom);            try {                TimeUnit.SECONDS.sleep(5);                int k = 6 + 5 + 8 + 9;            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(username + " finish using " + bathRoom);        }    }}

第二个类是Parent,也就是房子的使用者

class Parent implements Runnable {    House house;    String name;    public Parent(House house, String name) {        this.house = house;        this.name = name;    }    @Override    public void run() {        if (name.equals("mother")){            house.useBathRoom1(name);        }else{            house.useBathRoom2(name);        }    }}

首先验证同步方法之间的互斥

 public static void main(String[] args) {        House house=new House();        Parent mom=new Parent(house,"mother");        Parent father=new Parent(house,"father");        new Thread(mom).start();        new Thread(father).start();    }

运行结果

mother is using bathroommother finish using bathroomfather is using kitchenfather finish using kitchen

可以看到同步方法之间是互斥的,虽然mother用的是bathroom ,father使用的是kitchen,按理说浴室和厨房的共同使用是不冲突的,但是由于mother和father使用的都是同步方法,他们使用bathroom和kitchen方法是锁房门(也就是锁住整个house对象),只要有一个人使用了house中的资源,其它任何人都不能使用house的任何资源

浴室和厨房的共同使用时不冲突的,上述这样的使用明显是不合理的

我们进行如下的优化

我们将Parent中的run()方法进行如下的修改,修改成同步快使用资源

public void run() {        if (name.equals("mother")) {            house.useBathRoom2(name);        } else {            house.useKitchen2(name);        }    }

运行结果

mother is using bathroomfather is using kitchenfather finish using kitchenmother finish using bathroom

可以看到father 使用kitchen和mother使用bathroom之间没有任何干扰了,他们可以同时使用

实际上同步方法可以这样改成同步快

public void useKitchen(String username) {        synchronized (this) {            System.out.println(username + " is using " + kitChen);            try {                TimeUnit.SECONDS.sleep(5);                int i = 45 + 5;            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(username + " finish using " + kitChen);        }    }

this就相当于当前这个对象

静态同步方法和静态同步块使用上类似

只不过静态同步方法拿到的锁不是对象锁而是整个类的锁House.class,拿到这个锁后,某个线程使用静态同步方法其它任何线程都不能使用该类的静态同步方法

House.class这个锁和对象锁之间没有关系,看下面这个例子

还是修改Parent的run方法

if (name.equals("mother")) {            house.useBathRoom1(name);        } else {            House.repair(name);        }

运行结果

mother is using bathroomfather is repairing father finish repairing mother finish using bathroom

可以看到mother使用bathroom的同时不影响father repair。mother虽然拿到了house的对象锁,但是没有拿到House.class这个锁,所以这两者互不影响

注意:我们来看下面一个mother和father同时使用kitchen的例子,这两个并不会互斥

修改run方法为如下

@Override    public void run() {        if (name.equals("mother")) {            house.useKitChen1(name);        } else {            house.useKitchen2(name);        }    }

运行结果

mother is using kitchenfather is using kitchenmother finish using kitchenfather finish using kitchen

同步方法和非this同步块之间并没有互斥