synchronized同步锁,用synchronized修饰的方法,当有线程执行到这个方法时,都要检查以下有没有别的线程正在使用这个方法。以确保每刻始终只有一个线程执行这个方法。
根据synchronized作用的范围不同,可以分为以下两种:
1、作用于方法
2、作用于代码块
作用与方法时,可以用分为作用于普通方法和静态方法;作用于代码块有作用于实例对象、类对象和任意实例对象三种。
public class Test {
//注意,静态方法是作用于类而不是对象的,因此这里锁作用于Test.class类;不论new了几个实力对象,也都是只能获得一个锁。
public static synchronized void Method1() {
...
}
//实例方法,锁住的是该类的一个实例对象;因此如果new了两个实例对象,那么也将会获得不同的锁。
public synchronized void method2() {
...
}
public void method3() {
//同步代码块,锁住的是类对象
synchronized (Test.class) {
...
}
}
public void method4() {
//同步代码块,锁住的是类的实例对象
synchronized (Test.this) {
...
}
}
public void metho5(Object object) {
//同步代码块,锁住的是配置的实例对象
synchronized (object) {
...
}
}
}
对于类这个级别加锁有些太过于粗糙,因此可以在使用中对代码块进行加锁。
上面的分类也常常认为是三种:
1、在普通实例方法中使用;
2、在静态方法中使用;
3、在代码块中使用。
下面就对上面这三种作用情况分别举例子进行验证,再对运行结果进行分析:
0、先看一下不使用synchronized时的情况
class SynchronizedTest implements Runnable{
boolean flag = true;
// static SynchronizedTest test = new SynchronizedTest();
public void method1() {
// synchronized (this) {
Log.e("start", ">>>>>");
if (flag) {
Log.e("execute", ">>>>>");
flag = false;
}
Log.e("end", ">>>>>");
// }
}
@Override
public void run() {
// method1();
method1();
}
}
调用
final SynchronizedTest test1 = new SynchronizedTest();
final SynchronizedTest test2 = new SynchronizedTest();
Thread thread1 = new Thread(test1);
Thread thread2 = new Thread(test2);
// thread1.sleep(3000);
thread1.start();
thread2.start();
运行结果
可以看到如果不加锁,两个线程几乎是一起运行的,也没有先后问题的区分,更没有一个线程需要等待另一个线程运行结束再运行的情况。
1、在实例方法中使用
class SynchronizedTest implements Runnable{
boolean flag = true;
// static SynchronizedTest test = new SynchronizedTest();
public synchronized void method1() {
// synchronized (this) {
Log.e("start", ">>>>>");
if (flag) {
Log.e("execute", ">>>>>");
flag = false;
}
Log.e("end", ">>>>>");
// }
}
@Override
public void run() {
method1();
}
}
调用
final SynchronizedTest test1 = new SynchronizedTest();
final SynchronizedTest test2 = new SynchronizedTest();
Thread thread1 = new Thread(test1);
Thread thread2 = new Thread(test2);
// thread1.sleep(3000);
thread1.start();
thread2.start();
运行结果
这里可以看到,虽然加了锁,但是程序的运行结果并没有像我们想象的那样,这是因为在调用的时候,是new了两个实例对象,因此锁是对两个不同的对象加的,是相互不干扰的。
因此,在实例方法中使用应该是两个线程对于同一个实例方法进行操作
将调用部分的代码修改为:
final SynchronizedTest test1 = new SynchronizedTest();
// final SynchronizedTest test2 = new SynchronizedTest();
Thread thread1 = new Thread(test1);
Thread thread2 = new Thread(test1);
// thread1.sleep(3000);
thread1.start();
thread2.start();
运行结果
这样也就达到了第一个线程运行完全结束再运行第二个线程的目的。
2、在静态方法中使用
static class SynchronizedTest implements Runnable{
static boolean flag = true;
// static SynchronizedTest test = new SynchronizedTest();
public static synchronized void method1() {
// synchronized (this) {
Log.e("start", ">>>>>");
if (flag) {
Log.e("execute", ">>>>>");
flag = false;
}
Log.e("end", ">>>>>");
// }
}
@Override
public void run() {
method1();
}
}
调用
final SynchronizedTest test1 = new SynchronizedTest();
final SynchronizedTest test2 = new SynchronizedTest();
Thread thread1 = new Thread(test1);
Thread thread2 = new Thread(test2);
// thread1.sleep(3000);
thread1.start();
thread2.start();
运行结果
在静态方法中,也new了两个对象,但是运行结果不同于上面在实例方法中的,这是因为静态是针对类而不是对象的,也就是说不管是test1还是test2,他们都是SynchronizedTest类,synchronized锁是加在类范畴的。所以不管new了几个对象,在静态的修饰下都是只能获取一个锁的。
3、在代码块中使用
static class SynchronizedTest implements Runnable{
static boolean flag = true;
static SynchronizedTest test = new SynchronizedTest();
public void method1() {
Log.e("start", ">>>>>");
if (flag) {
Log.e("execute", ">>>>>");
flag = false;
}
Log.e("end", ">>>>>");
}
@Override
public void run() {
synchronized (test){
method1();
}
}
}
在主函数调用
Thread thread1 = new Thread(SynchronizedTest.test);
Thread thread2 = new Thread(SynchronizedTest.test);
// thread1.sleep(3000);
thread1.start();
thread2.start();
运行结果
运行结果可以看出来,当临界值flag改变时,第二个线程对应的flag也就发生了改变。
.
.
.
欢迎交流和指正