java synchronized详解--synchronized方法

上一章讲了synchronized代码块,这章说一下synchronize方法,及synchronized代码块与synchronized方法的联系

上一章说的synchronized代码块,主要说了synchronized锁(类似现实中的锁)的重要性和注意项
这章说一下synchronized修饰的方法的关键点和注意项
如果你拜读了java官方文档,你会知道synchronized方法也有锁(类似现实中的锁),那么它的锁(类似现实中的锁)是什么呢,下面通过代码和运行结果来找出答案

结构简述:

定义了一个资源PrintDemo3,一个线程类ThreadDemo3,一个测试类TestThread,在测试类中创建两个线程对象,两个线程对象都通过run方法访问资源PrintDemo.printCount方法

第一种场景:资源加锁在synchronized方法上
第一幕:
package com.yy.test;

/**
 * Created by skyler on 2017/2/17.
 */
class PrintDemo3 {
    public synchronized void printCount() {
        try {
            for(int i = 10; i > 0; i--) {
                System.out.println("Counter   ---   "  + i );
            }
        }catch (Exception e) {
            System.out.println("Thread  interrupted.");
        }
    }
}

class ThreadDemo3 extends Thread {
    private Thread t;
    private String threadName;
    PrintDemo3  PD;

    ThreadDemo3( String name,  PrintDemo3 pd) {
        threadName = name;
        PD = pd;
    }

    public void run() {
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        PD.printCount();
        System.out.println("Thread " +  threadName + " exiting.");
    }

    public void start () {
        System.out.println("Starting " +  threadName );
        if (t == null) {
            t = new Thread (this, threadName);
            t.start ();
        }
    }
}

public class TestThread {
    public static void main(String args[]) {
        TestThread tt = new TestThread();
        tt.test1();
    }

    public void test1() {
        PrintDemo3 PD = new PrintDemo3();
        PrintDemo3 PD3 = new PrintDemo3();

        ThreadDemo3 T1 = new ThreadDemo3( "Thread - 1 ", PD );
        ThreadDemo3 T2 = new ThreadDemo3( "Thread - 2 ", PD3 );

        T1.start();
        T2.start();

        // wait for threads to end
        try {
            T1.join();
            T2.join();
        }catch( Exception e) {
            System.out.println("Interrupted");
        }
    }
}

上面代码在PrintDemo3.printCount()上加了synchronized修饰符,表示这个方法是加锁了的。之后定义了两个PrintDemo3对象PD、PD3和两个ThreadDemo3线程对象T1、T2,并把PD、PD3分别传给T1、T2,见test1方法

运行后查看结果:

Starting Thread - 1 
Starting Thread - 2 
Counter   ---   10
Counter   ---   9
Counter   ---   8
Counter   ---   7
Counter   ---   6
Counter   ---   10
Counter   ---   9
Counter   ---   8
Counter   ---   7
Counter   ---   6
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 2  exiting.
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 1  exiting.

从结果得出,资源被两个线程同时访问了,synchronized方法的锁没有起作用。原因我们稍后再说,稍稍改一下代码

第二幕:

改一下代码:ThreadDemo3 T2 = new ThreadDemo3( “Thread - 2 “, PD3 ) 中的PD3改为PD

修改代码后运行,查看结果

Starting Thread - 1 
Starting Thread - 2 
Counter   ---   10
Counter   ---   9
Counter   ---   8
Counter   ---   7
Counter   ---   6
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 1  exiting.
Counter   ---   10
Counter   ---   9
Counter   ---   8
Counter   ---   7
Counter   ---   6
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 2  exiting.

从结果得出,实现了资源被线程独享
第一幕和第二幕代码的不同处只有传给两个线程的PrintDemo3对象不同。第一幕中两个线程T1、T2分别传递了PD、PD3。而第二幕中两个线程T1、T2都传递了PD。所以可以猜想,造成结果不同的原因也是由于锁(类似现实中的锁)的不同引起的。而修饰方法的synchronized的锁(类似现实中的锁)是synchronized方法所在类的对象实例,相当于synchronized方法等于方法里的synchronized(this)代码块,这里的this就是synchronized方法所在类的对象实例。

为了验证这个猜想,看第二种场景

第二种场景:资源加锁在方法内的synchronized(this)代码块上
package com.yy.test;

/**
 * Created by yaoliang on 2017/2/17.
 */
class PrintDemo3 {
    public void printCount() {
        synchronized(this) {
            try {
                for(int i = 10; i > 0; i--) {
                    System.out.println("Counter   ---   "  + i );
                }
            }catch (Exception e) {
                System.out.println("Thread  interrupted.");
            }
        }
    }
}

class ThreadDemo3 extends Thread {
    private Thread t;
    private String threadName;
    PrintDemo3  PD;

    ThreadDemo3( String name,  PrintDemo3 pd) {
        threadName = name;
        PD = pd;
    }

    public void run() {
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        PD.printCount();
        System.out.println("Thread " +  threadName + " exiting.");
    }

    public void start () {
        System.out.println("Starting " +  threadName );
        if (t == null) {
            t = new Thread (this, threadName);
            t.start ();
        }
    }
}

public class TestThread {
    public static void main(String args[]) {
        TestThread tt = new TestThread();
        tt.test1();
    }

    public void test1() {
        PrintDemo3 PD = new PrintDemo3();
        PrintDemo3 PD3 = new PrintDemo3();

        ThreadDemo3 T1 = new ThreadDemo3( "Thread - 1 ", PD );
        ThreadDemo3 T2 = new ThreadDemo3( "Thread - 2 ", PD3 );

        T1.start();
        T2.start();

        // wait for threads to end
        try {
            T1.join();
            T2.join();
        }catch( Exception e) {
            System.out.println("Interrupted");
        }
    }
}

场景二的代码与场景一99%是一样的,不同之处在PrintDemo3.printCount()方法上,把方法修饰符synchronized移到了此方法内,并把this作为synchronized的锁(类似现实中的锁)

第三幕:

两个线程T1、T2分别传递了PD、PD3

运行test1()方法并查看结果:

Starting Thread - 1 
Starting Thread - 2 
Counter   ---   10
Counter   ---   9
Counter   ---   8
Counter   ---   7
Counter   ---   10
Counter   ---   6
Counter   ---   9
Counter   ---   8
Counter   ---   7
Counter   ---   6
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 2  exiting.
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 1  exiting.
第四幕:

修改test1()方法代码为:

ThreadDemo3 T1 = new ThreadDemo3( "Thread - 1 ", PD );
ThreadDemo3 T2 = new ThreadDemo3( "Thread - 2 ", PD );

也就是两个线程T1、T2都传递了PD

运行test1()方法并查看结果:

Starting Thread - 1 
Starting Thread - 2 
Counter   ---   10
Counter   ---   9
Counter   ---   8
Counter   ---   7
Counter   ---   6
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 1  exiting.
Counter   ---   10
Counter   ---   9
Counter   ---   8
Counter   ---   7
Counter   ---   6
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 2  exiting.

从结果得出,实现了资源被线程独享

比较第一幕和第三幕,第二幕和第四幕,可以发现如下

结论:

synchronized方法等于方法中加入synchronized(this)代码块,也就是synchronized修饰方法时,synchronized的锁(类似现实中的锁)是调用这个方法的类的对象实例,如PD.printCount(),此时synchronized锁就是PD;而PD3.printCount(),此时synchronized锁就是PD3

以上说了synchronized应用级的用法,关于内部原理实现,我的水平还有待提高,请看下面关于原理的讲解:

http://www.importnew.com/23511.html
https://www.quora.com/How-does-synchronize-work-in-Java
http://blog.takipi.com/5-things-you-didnt-know-about-synchronization-in-java-and-scala/
http://gee.cs.oswego.edu/dl/cpj/jmm.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值