java synchronized关键字详解(一)

2014-11-24 07:25:44 · 作者: · 浏览: 0

一、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_e