synchronized可以修饰代码块和方法,方法又分为静态方法和普通方法,那么一言概之:线程执行的时候当有synchronized时,他获取的是类锁或实例锁然后才能执行。
代码准备:
构造四类同步方法:
public synchronized void a() {
System.out.println("a");
try {
Thread.sleep(10000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void b() {
System.out.println("b");
}
public static synchronized void c() {
System.out.println("static c");
try {
Thread.sleep(10000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void d() {
System.out.println("static d");
}
通过sleep来实现操作差
案例1:如果某一对象有多个同步方法,那么其只能排队访问其对应的同步方法,因为此时是对象锁
public static void testInstance1() {
final ThreadTest t1 = new ThreadTest();
new Thread(new Runnable() {
@Override
public void run() {
t1.a();
}
}, "T1").start();
new Thread(new Runnable() {
@Override
public void run() {
t1.b();
}
}, "T2").start();
}
输出:
a
然后开始等待,方法a执行完之后输出b
案例2:多个实例,访问各自不同的同步方法时不受影响:
public static void testInstance2() {
final ThreadTest t1 = new ThreadTest();
final ThreadTest t2 = new ThreadTest();
new Thread(new Runnable() {
@Override
public void run() {
t1.a();
}
}, "T1").start();
new Thread(new Runnable() {
@Override
public void run() {
t2.b();
}
}, "T2").start();
}
输出:
a
b
方法a未执行结束
案例3:当同步访问静态方法和非静态方法时不受影响,因为他们是两个不同的锁,静态方法是类锁而非静态方法为实例锁:
public static void testInstance3() {
final ThreadTest t1 = new ThreadTest();
new Thread(new Runnable() {
@Override
public void run() {
t1.a();
}
}, "T1").start();
new Thread(new Runnable() {
@Override
public void run() {
ThreadTest.c();
}
}, "T2").start();
}
输出:
a
static c
而a方法未执行结束,实例锁未释放
案例4:当并发访问两个非静态方法是需要同步等待:
public static void testInstance4() {
new Thread(new Runnable() {
@Override
public void run() {
ThreadTest.c();
}
}, "T2").start();
new Thread(new Runnable() {
@Override
public void run() {
ThreadTest.d();
}
}, "T1").start();
}
输出:
static c
等c执行完成之后释放了类锁之后输出static d
结论:
1.静态方法锁的是类,而非静态方法锁的是当前的实例,两把不同的锁互不影响;
2.类锁只有一把,而不同的实例其锁不同;
3.静态代码块效果等同;