synchronized是Java关键字,为多线程场景下防止临界资源访问冲突提供支持,当任务要执行别synchronized关键字保护的代码时,它将检查锁是否可用,然后获取锁,执行代码,最后再释放锁。有三种用法:synchronized方法、
synchronized静态方法、synchronized代码块。
1.synchronized方法
首先看一下没有加synchronized关键字执行下面程序的结果:
public class TreadTest {
public void method1(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method1");
}
public void method2() {
System.out.println("method2");
}
public static void main(String[] args) {
TreadTest test = new TreadTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
test.method1();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
test.method2();
}
});
t1.start();
t2.start();
}
上面代码中,method1比method2多了1s的延时,因此在t1和t2线程同时执行的情况下,先打印出method2的执行结果:
method2
method1
当method1和method2加上synchronized关键字后,代码如下:
public synchronized void method1(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method1");
}
public synchronized void method2() {
System.out.println("method2");
}
此时,由于method1占用了锁,因此method2必须要等待method1执行完之后才能执行,因此先打印出method1的执行结果:
method1
method2
因此
synchronized锁定是当前的对象,当前对象的synchronized方法在同一时间只能执行其中的一个,另外的synchronized方法需挂起等待,但不影响非synchronized方法的执行。下面的synchronized方法和synchronized代码块(把整个方法
synchronized
(
this
)包围起来)等价的。
public synchronized void method1(){
}
public void method2() {
synchronized(this){
}
}
2.synchronized静态方法
synchronized静态方法是作用在整个类上面的方法,相当于把类的class作为锁,示例代码如下:
public class TreadTest {
public static synchronized void method1(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("method1");
}
public static void method2() {
synchronized(TreadTest.class){
System.out.println("method2");
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
TreadTest.method1();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
TreadTest.method2();
}
});
t1.start();
t2.start();
}
}
由于将class作为锁,因此method1和method2存在着竞争关系,method2中synchronized(ThreadTest.class)等同于在method2的声明时void前面直接加上synchronized。上述代码的执行结果仍然是先打印出method1的结果:
method1
method2
3. synchronized代码块
synchronized代码块应用于处理临界资源的代码块中,不需要访问临界资源的代码可以不用去竞争资源,减少了资源间的竞争,提高代码性能。示例代码如下:
public class TreadTest {
private Object obj = new Object();
public void method1(){
System.out.println("method1 start");
synchronized(obj){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("method1 end");
}
}
public void method2() {
System.out.println("method2 start");
// 延时10ms,让method1线获取到锁obj
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(obj){
System.out.println("method2 end");
}
}
public static void main(String[] args) {
TreadTest test = new TreadTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
test.method1();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
test.method2();
}
});
t1.start();
t2.start();
}
}
执行结果如下:
method1 start
method2 start
method1 end
method2 end
上述代码中,执行method2方法,先打印出 method2 start, 之后执行同步块,由于此时obj被method1获取到,method2只能等到method1执行完成后再执行,因此先打印method1 end,然后在打印method2 end。