其实如果不懂,自己写一个例子出来跑一跑,就什么都知道了。
synchronized一共两种用法:
1、放在方法前面声明方法
2、synchronized(xxx){ //TODO} 形成代码块
第一种放在方法前面声明方法时,即:
public synchronized void func(){
//TODO
}
假设此方法分别被Thread_1和Thread_2两条线程无限循环地调用,那么此时的调用顺序为:
可以看到,当方法被线程1调用完,就会立刻被线程2调用;线程2调用完毕,又会立刻被线程1调用,该方法是不会被同时调用的。
第二种代码块的方法,用于作为线程锁的东西有很多,分别有:
1、普通对象
public Object mLock = new Object();
public void func(){
synchronized(mLock){
//TODO
}
}
这种写法是针对同一个对象中,多条线程的同步问题的。
假如我在一个对象中,有多个内部方法都用到了这个锁,然后分别被多个线程所调用,那么线程间会根据这个mLock成员的监控情况进行线程同步。
比如,当前有func1()、func2()、func3()、func4()四个方法都用到这个代码块线程锁,而有Thread_1、Thread_2、Thread_3、Thread_4条线程分别调用这四个方法并同时开启线程。虽然线程是同步开启,但是从哪个线程开始先执行是不确定的,我们假设线程1先被执行,此时mLock被fun1中的代码块所监控着,线程2、3、4都必须等待这个mLock被释放了,才可以继续运行,否则将一直等待,直到线程1中的fun1被执行完成,然后mLock被释放为止。
2、静态对象
public static Object mLock = new Object();
调用方法和上述1中的方式一样,不同之处在于代码块中的线程锁对象为静态对象。
静态对象是针对同一个类的多个对象中,每个对象之间的线程同步问题的。
举个例子,在一个类中,有一个静态变量:
public static int index = 0;
此时我们生成了3个这个类的对象,每个实例都可以调用线程改变这个index,比如为其递增1(index++)。并且加到index = 20时就退出不再改变。
如果不进行线程同步,就会发生index被同时index++,此时index将出现超过20的情况。所以就要用到这个静态对象的锁,保证多个对象之间各自的线程能保持同步。
3、synchronized(this)
这里的用法和上述1中的意思和作用一样,不同的是,1中用的锁的成员为自己定义的Object,而这里的锁的成员为当前类的实例。
比如,当前有一个类Class_1,这个类中的方法用了这个synchronized(this)。而这个类所生成了两个对象class_object_1和class_object_2。那么对于这两个对象而言,他们的synchronized(this)中的this就是指其对象本身,即class_object_1这个对象的中的synchronized(this)中的this指的是class_object_1。
4、synchronized(Class.this)
这里的用法和上述2中的意思和作用一样。