Android 多线程之synchronized锁住的是代码还是

2019-03-04  本文已影响0人  有没有口罩给我一个

Android 线程简单分析(一)
Android 并发之synchronized锁住的是代码还是对象(二)
Android 并发之CountDownLatch、CyclicBarrier的简单应用(三)
Android 并发HashMap和ConcurrentHashMap的简单应用(四)(待发布)
Android 并发之Lock、ReadWriteLock和Condition的简单应用(五)
Android 并发之CAS(原子操作)简单介绍(六)
Android 并发Kotlin协程的重要性(七)(待发布)
Android 并发之AsyncTask原理分析(八)(待发布)
Android 并发之Handler、Looper、MessageQueue和ThreadLocal消息机制原理分析(九)
Android 并发之HandlerThread和IntentService原理分析(十)

在java中多线程并发时,多个线程同时请求一个共享资源,必然会导致此资源的数据不安全,可能我们就需要synchronized同步避免线程并发访问共享资源导致数据不安全,但是synchronized锁住的是代码还是对象?

看一下栗子:

public class SynchronizedExample {

 public synchronized void share() {
    Log.e("tag", "share 开始执行.....");
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Log.e("tag", "share 结束.....");
    }
}

  class SynchronizedExampleThread extends Thread {
    @Override
    public void run() {
        SynchronizedExample example = new SynchronizedExample();
        example.share();
    }
}

1、在SynchronizedExample 的share方法加synchronized 打印结果:

share 开始执行.....
share 开始执行.....
share 开始执行.....
share 结束.....
share 结束.....
share 结束.....

可以看出来,上面的起动了三个线程,同时运行SynchronizedExample 类中的share方法,虽然share方法加上了synchronized,但是还是同时运行起来,好像synchronized并没起到同步的这用作用?

再来改改,改成同步代码块?

 public void share() {
    synchronized (this) {
        Log.e("tag", "share 开始执行.....");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.e("tag", "share 结束.....");
    }
} 

结果还是和上面的一样

share 开始执行.....
share 开始执行.....
share 开始执行.....
share 结束.....
share 结束.....
share 结束.....

在java中,synchronized(this)以及非static的synchronized方法,只能防止多个线程同时执行同一个对象的同步代码段,即同一个锁监视器。
分析一下上面的代码?

实际上,在java中,对于非static的synchronized方法或者是synchronized代码块,锁的就是对象本身也就是this。是不是有答案了?

synchronized锁住的是括号里的对象,而不是代码。

当synchronized锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待(同步队列)这个线程执行完成释放锁,才能再次给对象加锁,这样才达到线程同步的目的,如果不明白可以看Android 线程简单分析(一)介绍,很详细。

所以我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步。这叫减小锁的粒度,使代码更大程度的并发。锁的代码段太长了,别的线程是不是要等很久。

再看上面的代码,每个线程中都new了一个SynchronizedExample 类的对象,也就是产生了三个SynchronizedExample 对象,由于不是同一个对象,所以可以多线程同时运行synchronized方法或代码段。

验证:

 SynchronizedExample example = new SynchronizedExample();
class SynchronizedExampleThread extends Thread {
    @Override
    public void run() {
        example.share();
    }
}

结果:

 share 开始执行.....
 share 结束.....
 share 开始执行.....
 share 结束.....
 share 开始执行.....
 share 结束.....

synchronized就起了作用。

为了在明确一点我在创建两个SynchronizedExample 对象:

  SynchronizedExample example = new SynchronizedExample();
  SynchronizedExample example2 = new SynchronizedExample();

class SynchronizedExampleThread extends Thread {
    @Override
    public void run() {
        example.share();
    }
}

class SynchronizedExampleThread2 extends Thread {
    @Override
    public void run() {
        example2.share2();
    }
}

结果:

share 开始执行.....
share2 开始执行.....
share 结束.....
share 开始执行.....
share2 结束.....
share2 开始执行.....
share 结束.....
share 开始执行.....
share2 结束.....
share2 开始执行.....
share 结束.....
share2 结束.....

明显同一个所得是同一个对象,即同一把锁。

未命名文件.png
上一篇下一篇

猜你喜欢

热点阅读