lazzyRabbit hello

synchronized

每一个用synchronized关键字声明的方法都是临界区。在Java中,同一个对象的临界区,在同一时间只有一个允许被访问。当一个线程试图访问一个临界区时,它将使用一种同步机制来查看是不是已有其他线程进入临界区。如果没有其他线程进入临界区,它就可以进入临界区;如果已有线程进入了临界区,它就被同步机制挂起,直到进入的线程离开这个临界区。如果在等待进入临界区的线程不止一个,JVM会随机选择其中的一个,其余的将继续等待。

使用方式

1、synchronized方法

    public synchronized void method() {
         //代码
    }

修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁

修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁

2、synchronized代码块

synchronized(obj)  
{  
    //代码块  
}  

其中可将synchronized作用于一个给定的实例对象obj,每次当线程进入synchronized包裹的代码块时就会要求当前线程持有obj实例对象锁,如果当前有其他线程正持有该对象锁,那么新到的线程就必须等待,同时也可以使用this对象,代表当前实例,相当于synchronized修饰实例方法,或者当前类的class对象作为锁,相当于synchronized修饰静态方法。

以下是一个验证synchronized静态方法与synchronized代码块使用类锁获取的是同一把锁的例子:

public class TestSynchronizedMethod {

    // 方法1-synchronized块(对象级)
    public void method1() {
        synchronized (this) {
            try {
                for (int i = 0; i < 10; i++) {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName()+" synchronized块(对象级)");
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    // 方法2-synchronized块(类级别)
    public void method2() {
        synchronized (TestSynchronizedMethod.class) {
            try {
                for (int i = 0; i < 10; i++) {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName()+" synchronized块(类级别)");
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    // 方法3-synchronized 普通方法
    public synchronized void method3() {
        try {
            for (int i = 0; i < 10; i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName()+" synchronized普通方法");
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // 方法4-synchronized 静态方法
    public static synchronized void method4() {
        try {
            for (int i = 0; i < 10; i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName()+" synchronized静态方法");
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
public class TestThread implements Runnable {

    private TestSynchronizedMethod syncT;
    private int method;

    public TestThread(TestSynchronizedMethod syncT, int method) {
        this.syncT = syncT;
        this.method = method;
    }

    @Override
    public void run() {
        if (method == 1)
            syncT.method1();
        if (method == 2)
            syncT.method2();
        if (method == 3)
            syncT.method3();
        if (method == 4)
            syncT.method4();
    }

}
public class TestMain {

    public static void main(String[] args) throws InterruptedException {
        TestSynchronizedMethod tsm = new TestSynchronizedMethod();
        TestSynchronizedMethod tsm2 = new TestSynchronizedMethod();
        TestThread test1 = new TestThread(tsm,2);
        TestThread test2 = new TestThread(tsm,4);
        Thread temp1 = new Thread(test1, "thread1");
        Thread temp2 = new Thread(test2, "thread2");
        temp1.start();
        temp2.start();
    }
}

执行结果如下,thread2在thread1执行结束之后才会执行,同时可以改变main方法中的参数来验证其他结果。

thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread1 synchronized块(类级别)
thread2 synchronized静态方法
thread2 synchronized静态方法
thread2 synchronized静态方法
thread2 synchronized静态方法
thread2 synchronized静态方法
thread2 synchronized静态方法
thread2 synchronized静态方法
thread2 synchronized静态方法
thread2 synchronized静态方法
thread2 synchronized静态方法

#Point

用synchronized关键字声明的静态方法,同时只能被一个执行线程访问,但是其他线程可以访问这个对象的非静态方法。即:两个线程可以同时访问一个对象的两个不同的synchronized方法,其中一个是静态方法,一个是非静态方法。原因在于它们获取的锁不同,一个获取的是当前对象的锁,另一个获取的是类锁。

synchronized关键字不能继承

在定义接口方法时不能使用synchronized关键字。

构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。