Android 多线程之synchronized锁住的是代码还是对象(二)
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同一个对象每条线程进入同步代码块,其他线程将进入同步队列或锁池中等待其他线程释放锁,synchronize属于非公平锁,在锁池的等待的线程在线程1释放锁开始竞争锁,所以synchronize锁的是对象。
非公平锁和公平锁
1、非公平锁:线程加锁时直接尝试获取锁,获取不到就自动到队尾等待,ReentrantLock(默认)和synchronize属于非公平锁。
2、公平锁:加锁前先查看是否有排队等待的线程,有的话优先处理排在前面的线程,先来先得。乐观锁和悲观锁
1、悲观锁:假设一定会发生并发冲突,通过阻塞其他所有线程来保证数据的完整性,就是属于悲观主义,synchronize就是悲观锁。
2、乐观锁:假设不会发生并发冲突,直接不加锁去完成某项更新,如果冲突就返回失败,CAS机制属于乐观的。
更多相关文章
- Android Handler机制5之Message简介与消息对象对象池
- Android——多线程
- input系统一 loop线程的创建与运行
- Android——导入已存在的android工程时出现红叉错误“AndroidMan
- AndroidUI线程机制
- android的大好时光结束进行时
- Android 对象序列化之你不知道的 Serializable
- Android 对象序列化之 Parcelable 取代 Serializable ?
- Android 对象序列化之追求完美的 Serial