锁
比如有三个线程thread-0, thread-1, thread-3
三个线程同时在执行一个带锁的方法时,如果thread-0先获得了锁,那么其它二个线程就只能外面等着,直到thread-0把锁给释放了,这个时候就由其它线程去争取这个锁.
生活中的例子: 现在有三个人同时都要上厕所A,B,C . A先进入到了厕所,这个时候A就会把门给锁了,B,C就要在外面等,直到A上完出来把门打开,这个时候B,C才能有一个人进去,进去后也是锁门,出来也是解锁,然后继续下一个人.
锁可以解决多线程中线程安全的问题.
在android中的单例(懒汉式)
public class SingleTon {
private static SingleTon sInstance;
public static SingleTon getInstance() {
if (sInstance ==null) {
//1:
sInstance = new SingleTon();
}
return sInstance;
}
}
如果多线程调用这个getInstance的话就会有问题,下面分析一下
同样有三个线程: thread-0, thread-1, thread-2
注释1处: 假如thread-0执行到1处时候cpu执行器被操作系统调度给释放了,这时thread-1进来了,发现sInstance是空的,就会执行下new代码,最后执行完了,这个时候thread-0恢复了获得了cpu执行权,thread-0也new出了一个,这样这个sInstance被创建了二次,就会引发安全性问题
解决方法,加synchronized锁住,被称之为隐式锁,因为加锁解锁我们都看不到,是内部自己完成的.
public class SingleTon {
private static SingleTon sInstance;
public synchronized static SingleTon getInstance() {
if (sInstance ==null) {
sInstance = new SingleTon();
}
return sInstance;
}
}
synchronized使用方法
作用在静态方法之上执行的是一个类锁xxx.class
作用在非静态方法之上执行的是当前的对象锁Object object;
上面那个写法会有性能问题,因为每个线程都会在方法外等待,所以性能不是非常好,改进版本
public class SingleTon {
private static SingleTon sInstance;
public static SingleTon getInstance() {
if (sInstance == null) {
synchronized (SingleTon.class) {
if (sInstance == null) {
sInstance = new SingleTon();
}
}
}
return sInstance;
}
}
这二种方法执行的锁其实是同一个锁
这里再多提一嘴静态方法的synchronized和非静态方法的区别
public class SingleTon {
private static SingleTon sInstance;
public synchronized static SingleTon getInstance() {
if (sInstance ==null) {
sInstance = new SingleTon();
}
return sInstance;
}
}
public class SingleTon {
private static SingleTon sInstance;
public static SingleTon getInstance() {
synchronized(SingleTon.class){
if (sInstance ==null) {
sInstance = new SingleTon();
}
}
return sInstance;
}
}
上面二个方法是等价的
public class SingleTon {
private static SingleTon sInstance;
public synchronized SingleTon getInstance() {
if (sInstance ==null) {
sInstance = new SingleTon();
}
return sInstance;
}
}
public class SingleTon {
private static SingleTon sInstance;
public SingleTon getInstance() {
synchronized(this){
if (sInstance ==null) {
sInstance = new SingleTon();
}
}
return sInstance;
}
}
这上面二个方法也是等价的
显示锁 Lock: 我们程序员可以自己控制
在下面这个demo中可以发现在二个线程都执行add这个方法的时候会出现线程安全问题,解决方法有二种
1:在方法上加个synchronized,第二种方法使用Lock这个来操作加锁解锁, synchronized天生是可重入锁
public class LockDemo {
private int mCount = 0;
private Lock mLock = new ReentrantLock();//这是一个可重入锁
public void add() {//有问题
mCount++;
}
public void add() {//没问题
mLock.lock();//自己加锁
mCount++;//如果这里发生异常,下面就不会解锁,就会导致所有线程都进不来
mLock.unlock();//自己解锁
}
public void add() {//没问题
try {
mLock.lock();
mCount++;
}finally {
mLock.unlock();
}
}
public synchronized void add() {//没问题
mCount++;
}
private static class MyThread extends Thread {
LockDemo mLockDemo;
public MyThread(LockDemo lockDemo) {
mLockDemo = lockDemo;
}
@Override
public void run() {
super.run();
for (int i = 0; i < 10000; i++) {
mLockDemo.add();
}
}
}
public static void main(String[] args) {
LockDemo lockDemo = new LockDemo();
new MyThread(lockDemo).start();
new MyThread(lockDemo).start();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("count: " + lockDemo.mCount);
}
}