【并发】android中的synchronized 1 使用synchronized修饰方法 2 使用synchronized修饰代码块

synchronized用于多线程访问,并且被修饰的部分不能同时被执行,是代码同步的一种方式。

1 使用synchronized修饰方法

1.1 synchronized修饰方法原理

  • 过程:当多个线程同时访问被synchronized修饰的方法是,有且仅有一个线程可以被访问,当一个线程在访问时,其它线程只能等待。当一个线程访问完毕后,下一个线程才可以访问。
  • 原理:当方法被synchronized修饰后,如果想要执行该方法就必须获得相应的锁。每个类有且仅有一个锁(针对静态方法),每个类的实例也是有且仅有一个锁。当多个线程在同时访问同一个方法时,执行该方法就必须获得相应的锁,同时锁只有一个,所以只能有一个线程可以获得锁,其它的线程必须等待该线程释放锁后才能获取到该锁。
  • 进阶说明:由于每个类只有一个锁,所以当一个类中有多个方法被synchronized修饰时,在同一时间内只能有一个方法可以获得锁,所以只有一个被synchronized修饰的方法可以执行。

1.2 synchronized修饰方法示例

    public void showDo(String msg){
        for(int i=0;i<1000000;i++){
            if (i%100000==0){
                System.out.println("打印结果"+msg+i/100000);
            }
        }
    }

//使用
        new Thread(){
            @Override
            public void run() {
                super.run();
                showDo("线程一");
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                super.run();
                showDo("线程二");
            }
        }.start();

结果:


未加synchronized修饰方法,可以看到执行顺序是打乱的,无序的。加了synchronized后:

    public synchronized void showDo(String msg){
        for(int i=0;i<1000000;i++){
            if (i%100000==0){
                System.out.println("打印结果"+msg+i/100000);
            }
        }
    }

结果


2 使用synchronized修饰代码块

2.1使用synchronized修饰代码块说明

当使用synchronized在修饰代码块的时候需要一个自定义锁,当在多线程访问代码块的时候,只要获得自定义锁就可以执行。自定义锁可以是一个类,也可以是一个实例(可以是Object的子类,也可以是当前类自己),当具有相同自定义锁时代码块会顺序执行,当锁不同的时候互不影响。

2.2 使用synchronized修饰代码块示例

    private static String s1 = "";
    private static String s2 = "aa";

    public void showDo(String msg) {
        synchronized (s1){
            for (int i = 0; i < 1000000; i++) {
                if (i % 100000 == 0) {
                    System.out.println("打印结果" + msg + i / 100000);
                }
            }
        }
    }

    public void showDo1(String msg) {
        synchronized (s2){
            for (int i = 0; i < 1000000; i++) {
                if (i % 100000 == 0) {
                    System.out.println("打印" + msg + i / 100000);
                }
            }
        }
    }

//调用
        new Thread() {
            @Override
            public void run() {
                super.run();
                showDo1("线程一");
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                super.run();
                showDo("线程二");
                showDo1("线程二");
            }
        }.start();

结果:


由上可得,多个同步锁,只有竞争同一个同步锁才会需要等待,不是竞争同一个锁的代码块互不影响。

  • synchronized不能修饰构造函数
  • 定义接口方法时不能使用synchronized
  • synchronized(this)锁的是当前对象,当前有几个对象,this就有多少份
  • synchronized(XX.class)这个与当前对象无关,只要锁是XX.class的都会被同步
  • 如果同一个类中有多个方法使用了同步锁synchronized(this)或者多个方法被synchronized修饰,则多个线程访问该类中同步方法时,每次只能访问一个,其它的被阻塞。如:
public synchronized void A(){
    ......
}
public synchronized void B(){
    ......
}

有两个线程分别访问同一个对象T的A方法和B方法,则同时只能有一个方法被其中一个线程访问,另一个线程处于阻塞状态,因为方法A和B持有同一个对象锁,synchronized(this)也是类似的情况。

  • 同一个类中有多个方法使用了同步锁synchronized修饰,且这些类是静态的,因为静态方法是属于类的,而不是属于某个对象的,所以它与synchronized(XX.class)类似。
public synchronized static void method() {
   // todo
}
  • 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
  • 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章