synchronized,Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这个段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块。
1、可以对一个方法使用,例如:
public synchronized void test() {
System.out.println("test开始..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("test结束..");
}
2、也可以对一段代码使用,例如:
public void test() {
synchronized (Sync.class) {
System.out.println("test开始..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("test结束..");
}
}
3、synchronized后面括号里是一对象,此时,线程获得的是对象锁,例如:
public class MyThread implements Runnable{
public static void main(String args[]){
MyThread mt = new MyThread();
Thread t1 = new Thread(mt,"t1");
Thread t2 = new Thread(mt,"t2");
Thread t3 = new Thread(mt,"t3");
Thread t4 = new Thread(mt,"t4");
Thread t5 = new Thread(mt,"t5");
Thread t6 = new Thread(mt,"t6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
public void run(){
synchronized(this){
System.out.println(Thread.currentThread().getName());
}
}
}
对于3,如果线程进入,则得到当前对象锁,那么别的线程在该类所有对象上的任何操作都不能进行。在对象级使用锁通常是一种比较粗糙的方法。为什么要将整个对象都上锁,而不允许其他线程短暂地使用对象中其他同步方法来访问共享资源?如果一个对象拥有多个资源,就不需要只为了让一个线程使用其中一部分资源,就将所有线程都锁在外面。由于每个对象都有锁,可以如下所示使用虚拟对象来上锁:
class FineGrainLock{
MyMember Class x,y;
Object xlock=new Object(),ylock=new Object();
public void foo(){
synchronized(xlock){
//access x here
}
//do something here-but don't use shared resources
synchronized(ylock){
//access y here
}
}
public void bar(){
synchronized(this){
//access both x and y here
}
//do something here-but don't use shared resources
}
}
4、synchronized后面括号里是类,此时,线程获得的是对象锁。例如:
class ArrayWithLockOrder {
private static long num_locks = 0;
private long lock_order;
private int[] arr;
public ArrayWithLockOrder(int[] a)
{
arr=a;
synchronized(ArrayWithLockOrder.class){//-----这里
num_locks++; //锁数加1。
lock_order = num_locks;//为此对象实例设置唯一的lock_order。
}
}
public long lockOrder()
{
return lock_order;
}
public int[] array()
{
return arr;
}
}
class SomeClass implements Runnable {
public int sumArrays(ArrayWithLockOrder a1, ArrayWithLockOrder a2)
{
int value=0;
ArrayWithLockOrder first = a1; //保留数组引用的一个
ArrayWithLockOrder last = a2; //本地副本。
int size = a1.array().length;
if(size == a2.array().length) {
//确定并设置对象的锁定
if(a1.lockOrder() > a2.lockOrder()) {
//顺序。
first=a2;
last=a1;
}
//按正确的顺序锁定对象。
synchronized(first) {
synchronized(last) {
int[] arr1 = a1.array();
int[] arr2 = a2.array();
for(int i=0; i<size; i++)
value += arr1[i]+arr2[i];
}
}
}
return value;
}
public void run(){
//
}
}
对于4,如果线程进入,则其它线程在该类中所有操作不能进行,包括静态变量和静态方法,实际上,对于含有静态方法和静态变量的代码块的同步,我们通常用4来加锁。
对于synchronized的一些理解:
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用。