欢迎进入西安甲骨文培训机构 乘车路线| 关于我们| 设为首页| 加入收藏
logo 服务热线
1 2 3 3

新闻动态

联系我们

咨询报名电话:
029-85568080,029-85427081
传真:029-85568080
地址:陕西省西安市长安南路355号华银大厦(西北政法大学老校区对面西安银行南侧)

优秀学员

技术中心 当前位置:首页 > 新闻动态 > 技术中心

java synchronized关键字详解

点击: 时间:2013-12-30
一、java中的线程同步与锁


什么是锁呢? 打个比方,就好比现实生活当中的门,每个门都有一把锁,每个同步代码块的入口都有一道“门”,而这道门是加了锁的,要进入这道门去做你想做的事情,必须要获取这个锁的钥匙。java中每个对象有且仅有一个锁,基本数据类型是没有锁的,不能用来同步。



二、java 中的synchronized关键字


synchronized关键字用来标识线程要执行它所作用的代码块所需要的锁。synchronized可以用于方法修饰也可以用于代码块。本质地讲,synchronized作用的是一个代码块。
1,synchronized修饰非静态方法时,该同步方法是在类当前实例的对象(也就是this)上同步,也就是需要获取类当前实例对象的锁才能执行该方法。当一个线程进入类的synchronized方法或在this上同步的代码块时,由于类的所有synchronized方法都是在this上同步的,因此其他线程除了不能该问当前该线程正在访问的方法外,也不能访问该类的其他synchronized方法或在this上同步的代码块。需要特别注意的是,这里所说的不能访问,仅仅指在当前实例的数据范围内。

如:

public class Test1 {
    public synchronized void f(){
        //方法体
    }
}

由于本质上synchronized是同步代码块,所以上面代码等价于:

public  void f(){
        synchronized(this){
            //方法体
        }
    }
2,synchronized修饰静态方法时,它是在整个类(即类的Class对象)上同步的,也就是说,当一个线程访问了标记为synchronized时,其他线程不能访问该类所有实例的任何synchronized static方法。看下面的代码:
package com.litl.java.test;
import java.util.concurrent.TimeUnit;
public class Test1 {
    public synchronized static void f(){
        System.out.println("f-start---------------");
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("f_end>>>>>>>>>>>>>>>>");
    }
     
    public synchronized void g() {
        System.out.println("g-start-----------");
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("g_end>>>>>>>>>>>>>");
    }
     
    public static void main(String[] args) {
        for(int i=0;i<10;i++){
            final Test1 t=new Test1();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    t.f();
                    t.g();
                }
            }).start();
        }
    }
}

打印结果:
f-start---------------
f_end>>>>>>>>>>>>>>>>
f-start---------------
g-start-----------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g_end>>>>>>>>>>>>>
f-start---------------
g-start-----------
g_end>>>>>>>>>>>>>
f_end>>>>>>>>>>>>>>>>
g-start-----------
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
g_end>>>>>>>>>>>>>
f_end>>>>>>>>>>>>>>>>
g-start-----------
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g_end>>>>>>>>>>>>>
f-start---------------
g-start-----------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
g_end>>>>>>>>>>>>>

可以看到,f()方法是同步执行的,而g()方法是交替执行的。

分析:

由于f()是static方法,加上synchronized后标识为它是在Class上同步的,而g()不是static方法,它是在this上同步的,这两个锁是不一样的,由于main方法中是多个类实例执行f()和g()方法,因此这里f()同步起了作用,而对g()的同步无效。

如果想要g()也同步,可以修改代码使g()在Class上同步:

public  void g() {
    synchronized(Test1.class){
        System.out.println("g-start-----------");
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("g_end>>>>>>>>>>>>>");
    }
}

打印结果:

f-start---------------
f_end>>>>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
f-start---------------
f_end>>>>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>
g-start-----------
g_end>>>>>>>>>>>>>


三、总结

1,每个对象都有一个锁,基本类型数据不能用来同步

2,谈到同步,首先要明确是在哪个对象上同步,只有两个线程在同一个对象上同步时,同步才会起效果

3,Class锁和类实例锁是不一样的,static被加锁时,如果非static方法不是在Class上同步,则其他没有获取Class锁的线程仍可以访问该方法。