synchronized用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
请记住,JAVA多线程中的synchronized关键字是对象锁,所谓对象锁,就是给某个对象加锁。
一. Synchronized用法
synchronized可以修饰实例方法,写在public和返回类型中间,如下形式:
public class MyObject {
public synchronized void methodA(int id) {
}
}
这里,synchronized 关键字锁住的是当前对象,这也是称为对象锁的原因。
methodA()是个实例方法,要想执行methodA(),需要以 对象.方法() 的形式进行调用(obj.methodA(),obj是MyObject类的一个对象,synchronized就是把obj这个对象加锁了。
上述代码也可以写成这样,与synchronized(this)等价:
public class MyObject {
public void methodA(int id) {
synchronized(this){
}
}
}
使用synchronized关键字同步一个明显的特点是:MyObject类中定义有多个synchronized修饰的实例方法时,若多个线程拥有同一个MyObject类的对象,则这些方法只能以同步的方式执行。即,执行完一个synchronized修饰的方法后,才能执行另一个synchronized修饰的方法。
如下代码,MyObject 有两个synchronized修饰的函数:
public class MyObject {
public synchronized void methodA(int id) throws InterruptedException {
System.out.println("methodA"+id+"开始..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("methodA"+id+"结束..");
}
public synchronized void methodB(int id) throws InterruptedException {
System.out.println("methodB"+id+"开始..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("methodB"+id+"结束..");
}
}
线程类代码:
public class ThreadA extends Thread {
private MyObject object;
private int id;
public ThreadA(MyObject object,int id) {
this.object = object;
this.id = id;
}
public void run() {
super.run();
try {
object.methodA(id);
object.methodB(id);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
主函数代码:
public static void main(String[] args) {
MyObject object = new MyObject();
for(int i=0;i<3;i++)
{
ThreadA th1 = new ThreadA(object, i);
th1.start();
}
}
执行输出:
methodA0开始..
methodA0结束..
methodA2开始..
methodA2结束..
methodB2开始..
methodB2结束..
methodA1开始..
methodA1结束..
methodB1开始..
methodB1结束..
methodB0开始..
methodB0结束..
可以看出methodA和methodB方法是顺序执行的。
二. 结论
从上可以看出,本文中讲述的 synchronized 锁的范围是整个对象。如果一个类中有多个synchronized修饰的同步方法,且多个线程持有该类的同一个对象(该类的相同的对象),尽管它们调用不同的方法,各个方法的执行也是同步的。
如果各个同步的方法之间没有共享变量,或者说各个方法之间没有联系,但也只能同步执行,这会影响效率。