Java Synchronized


Java里最常用的线程同步方式就是synchronized关键字了。查阅了相关资料,加上一些代码的实践,总算对这个关键字有了个初略的认识。

首先,它的使用方法。基本可以分为两种,方法同步和代码块同步。

//方法同步,加在方法上面,
public synchronized void method1() {
        System.out.println("This is one synchronized method!");
    }

//代码块同步,在同步的代码块上锁定对象
public void method2() {
         synchronized(object){
                System.out.println("This is one synchronized code!");
            }      
    }

其次,它的原理是对对象进行监控锁定。对于加了synchronized关键字的对象,同一时间,只能有一个线程访问或进入该对象。所以,对方法的锁定可以理解为synchronized(this)。有了这个认识就来考虑以下几个场景。
场景一: 同一个对象,两个synchronized方法被调用。

public class SynchronizedTest {
    public synchronized void method1() {
        System.out.println("Method 1 start");
        try {
            System.out.println("Method 1 execute");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 1 end");
    }

    public synchronized void method2() {
        System.out.println("Method 2 start");
        try {
            {
                System.out.println("Method 2 execute");
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 2 end");
    }

    public static void main(String[] args) {
        SynchronizedTest test1 = new SynchronizedTest();

        new Thread(new Runnable() {
            @Override
            public void run() {
                test1.method1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                test1.method2();
            }
        }).start();
    }
}

输出结果为:

Method 1 start
Method 1 execute
Method 1 end
Method 2 start
Method 2 execute
Method 2 end

可见结果是两个线程发生同步互斥。虽然调用了不同方法,但是锁定的是同一个对象,之前说过对实例方法的锁定等同于synchronized(this)。
场景二:两个对象,同一个方法被两个线程调用。

public class SynchronizedTest {
    public synchronized void method1() {
        System.out.println("Method 1 start");
        try {
            System.out.println("Method 1 execute");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 1 end");
    }

    public synchronized void method2() {
        System.out.println("Method 2 start");
        try {
            {
                System.out.println("Method 2 execute");
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 2 end");
    }
    
    public synchronized void method3(int num) {
        System.out.println("thread " + num +" start");
        try {
            {
                System.out.println("thread " + num +" execute");
                Thread.sleep(num*1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("thread " + num +"  end");
    }

    public static void main(String[] args) {
        SynchronizedTest test1 = new SynchronizedTest();
        SynchronizedTest test2 = new SynchronizedTest();

        new Thread(new Runnable() {
            @Override
            public void run() {
                test1.method3(2);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                test2.method3(1);
            }
        }).start();
    }
}

输出结果为:

thread 2 start
thread 2 execute
thread 1 start
thread 1 execute
thread 1 end
thread 2 end

可见,线程1后启动,先结束。没有发生线程同步。这是因为synchronized锁定的对象不同,一个是test1对象,另一个是test2对象。

场景三:两个对象,同一个方法,访问一个静态对象。

public class SynchronizedTest {
    private static String obj = "";

    public synchronized void method1() {
        System.out.println("Method 1 start");
        try {
            System.out.println("Method 1 execute");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 1 end");
    }

    public synchronized void method2() {
        System.out.println("Method 2 start");
        try {
                System.out.println("Method 2 execute");
                Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 2 end");
    }

    public void method3(int num) {
        synchronized (obj) {
            System.out.println("thread " + num + " start");
            try {

                System.out.println("thread " + num + " execute");
                Thread.sleep(num * 1000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread " + num + "  end");
        }
    }

    public static void main(String[] args) {
        SynchronizedTest test1 = new SynchronizedTest();
        SynchronizedTest test2 = new SynchronizedTest();

        new Thread(new Runnable() {
            @Override
            public void run() {
                test1.method3(2);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                test2.method3(1);
            }
        }).start();
    }
}

输出结果:

thread 2 start
thread 2 execute
thread 2 end
thread 1 start
thread 1 execute
thread 1 end

线程发生同步,虽然是两个不同的对象,但是锁定的确是同一个静态对象。所以,线程发生同步。可见,只要synchronized作用在static声明的对象上,线程都会发生同步。因为,static声明的对象只有一份在静态存储区。而synchronized的锁定目标就是同一个对象。
参考了这篇博客:http://www.cnblogs.com/paddix/p/5367116.html

你可能感兴趣的:(Java Synchronized)