今天复习了一下java中Synchronized等关于多线程的问题。

Synchronized是Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

Java的每个对象都有一个内部锁,如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。要调用该方法必须获得内部的对象锁。

     一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

     二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

     三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

     四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

    对此,每一条做简单的验证,对于第三条,统计一下两个线程的执行时间,代码如下:

public class UserInfo {
	public synchronized void display(){
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println( Thread.currentThread()+"display user info!");
		
	}
	public void display2(){
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println( Thread.currentThread()+"display user info!");
		
	}
}

对于一个UserInfo对象,如果两个线程t1,t2,同时执行display总共应该花费越6000ms,如果两个线程调用的是display2,应该是花费约3000s。

为了验证,在main函数中进行调用显示时间,可是发现main函数先执行完毕了。两个时间都是一样的很短。

为此,经过查找,发现一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待,该类即:CountDownLatch(java.util.concurrent包中)。其采用减记数的方式。当计数器减至0时,位于latch.await后的代码才会被执行。

由此可以如下统计两个线程的执行时间:

private static CountDownLatch latch;
private static void testGetTime(){
		final UserInfo user=new UserInfo();
		latch=new CountDownLatch(2);
		Thread t1=new Thread(new Runnable(){
			@Override
			public void run() {
				user.display();
				latch.countDown();
			}
		});
		Thread t2=new Thread(new Runnable(){
			@Override
			public void run() {
				user.display();
				latch.countDown();
			}
		});
		long startTime=System.currentTimeMillis();		
		t1.start();
		t2.start();
		try {
			latch.await();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		System.out.println("display spend time:"+(System.currentTimeMillis()-startTime));//结果为:6001
		
		latch=new CountDownLatch(2);
		Thread th1=new Thread(new Runnable(){
			@Override
			public void run() {
				user.display2();
				latch.countDown();
			}
		});
		Thread th2=new Thread(new Runnable(){
			@Override
			public void run() {
				user.display2();
				latch.countDown();
			}
		});
		long startTime2=System.currentTimeMillis();
		th1.start();
		th2.start();
		try {
			latch.await();
		} catch (InterruptedException e1) {
			e1.printStackTrace();//
		}
		System.out.println("display2 spend time:"+(System.currentTimeMillis()-startTime2));//结果为:3001
	}

结果符合预期。

java.util.concurrent包中,还有许多高级的类,值得我这样的菜鸟继续发掘。记之……