您的位置:首页 > 其它

第三部分 线程安全(3)——线程同步

2011-01-19 10:32 211 查看
当已经有线程在执行这段代码块时,其他的线程必须等待其执行完毕才能进入这段代码块——这就是所谓的线程同步。

一.单实例线程的同步锁

首先看个实例,由于缺少线程同步机制,导致线程执行结果的错误。

实例代码【TestSynchronizationUsingRunnable】



/**
 * TestSynchronizationUsingRunnable.java
 * 版权所有(C) 2011 cuiran2001@163.com
 * 创建:崔冉  2011-1-13 下午04:28:31
 */

package com.cayden.thread813;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 崔冉
 * @version 1.0.0
 * @desc
 */
public class TestSynchronizationUsingRunnable {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Runnable threadBody=new ThreadBody(new ArrayList());
		
		Thread threada=new Thread(threadBody,"ThreadA");
		
		Thread threadb=new Thread(threadBody,"ThreadB");
		threada.start();
		threadb.start();
	}

}
class ThreadBody implements Runnable
{
	List intList=null;
	public ThreadBody(List list){
		intList=list;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
//		synchronized(this){
			intList.add(new Integer(123));
			try{
				Thread.sleep(500);
			}catch (InterruptedException e) {
				// TODO: handle exception
			}
			System.out.println(Thread.currentThread().getName()+"/t共有元素:"+intList.size());
//		}
	
	}
	
}



运行结果:

ThreadA 共有元素:2
ThreadB 共有元素:2


造成这一结果的原因在于,当线程ThreadA 向列表中添加一个元素之后,线程ThreadB也向其中添加了一个元素,由此造成两个线程均认为列表中的元素个数为2,而事实上,在线程ThreadA完成添加之后列表中的元素个数只有1。 下面对代码进行修改,把注释部分去掉。


代码如下:



/**
 * TestSynchronizationUsingRunnable.java
 * 版权所有(C) 2011 cuiran2001@163.com
 * 创建:崔冉  2011-1-13 下午04:28:31
 */

package com.cayden.thread813;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 崔冉
 * @version 1.0.0
 * @desc
 */
public class TestSynchronizationUsingRunnable {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Runnable threadBody=new ThreadBody(new ArrayList());
		
		Thread threada=new Thread(threadBody,"ThreadA");
		
		Thread threadb=new Thread(threadBody,"ThreadB");
		threada.start();
		threadb.start();
	}

}
class ThreadBody implements Runnable
{
	List intList=null;
	public ThreadBody(List list){
		intList=list;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		synchronized(this){
			intList.add(new Integer(123));
			try{
				Thread.sleep(500);
			}catch (InterruptedException e) {
				// TODO: handle exception
			}
			System.out.println(Thread.currentThread().getName()+"/t共有元素:"+intList.size());
		}
	
	}
	
}




执行结果:

ThreadA	共有元素:1
ThreadB	共有元素:2




“synchronized(this)”中的this代表锁定的对象实际上是Runnable对象,而一旦锁定了Runnable对象,便实现了线程同步。


二.多实例线程的同步锁

上面说的是单实例,多线程,现在说多实例,多线程。多线程没有基于共同的线程对象,那么如何实现它们之间的同步呢?
首先看一下同步之前的代码【TestSynchronizationUsingThread】


/**
 * TestSynchronizationUsingThread.java
 * 版权所有(C) 2011 cuiran2001@163.com
 * 创建:崔冉  2011-1-13 下午04:51:04
 */

package com.cayden.thread813;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 崔冉
 * @version 1.0.0
 * @desc
 */
public class TestSynchronizationUsingThread {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final List intList=new ArrayList();
		Thread threada=new Thread("ThreadA")
		{
			public void run(){
//				synchronized(intList){//同步
					intList.add(new Integer(0));
					try{
						Thread.sleep(500);
					}catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"/t最后一个元素:"+intList.get(intList.size()-1));
//				}
				
				
			}
		};
		Thread threadb=new Thread("ThreadB")
		{
			public void run(){
//				synchronized(intList){//同步
					intList.add(new Integer(1));
					try{
						Thread.sleep(500);
					}catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"/t最后一个元素:"+intList.get(intList.size()-1));
//				}
			}
		};
		threada.start();
		threadb.start();
		
	}

}


执行结果:


ThreadA 最后一个元素:1

ThreadB 最后一个元素:1



/**
 * TestSynchronizationUsingThread.java
 * 版权所有(C) 2011 cuiran2001@163.com
 * 创建:崔冉  2011-1-13 下午04:51:04
 */

package com.cayden.thread813;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 崔冉
 * @version 1.0.0
 * @desc
 */
public class TestSynchronizationUsingThread {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final List intList=new ArrayList();
		Thread threada=new Thread("ThreadA")
		{
			public void run(){
				synchronized(intList){//同步
					intList.add(new Integer(0));
					try{
						Thread.sleep(500);
					}catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"/t最后一个元素:"+intList.get(intList.size()-1));
				}
				
				
			}
		};
		Thread threadb=new Thread("ThreadB")
		{
			public void run(){
				synchronized(intList){//同步
					intList.add(new Integer(1));
					try{
						Thread.sleep(500);
					}catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"/t最后一个元素:"+intList.get(intList.size()-1));
				}
			}
		};
		threada.start();
		threadb.start();
		
	}

}




执行结果:
ThreadA 最后一个元素:0
ThreadB 最后一个元素:1


至此,我们可以对同步锁做出一个定义:当线程执行到synchronized的时候,检查传入的实参对象,并得到该对象的锁旗标。如果得不到,那么线程就会被加入到一个与该对象的锁旗标相关联的等待线程池中,一直等到对象的锁旗标被归还,池中的等待线程就会得到该锁旗表,如何继续执行下去。当线程执行完成同步代码块,就会自动释放,它占有的同步对象的锁旗标。


三.线程死锁

在启用同步锁机制后,有两种对象是需要避免的。一是无限等待,二是循环等待。都会导致线程死锁。


1.无限等待:线程B等待线程A完成同步锁内的代码块后释放同步锁,然而线程A却陷入了死循环。导致无法释放同步锁,这将进一步导致线程B陷入无限等待。例如:
synchronized(this)
{
while(true)
{....}
}
2. 循环等待:线程A锁住了对象1,等待对象2的释放,线程B锁住了对象2,等待对象1的释放,从而造成了死锁。
下面代码就是对死锁进一步的解释。

/**
 * TestDeadLock.java
 * 版权所有(C) 2011 cuiran2001@163.com
 * 创建:崔冉  2011-1-13 下午05:03:56
 */

package com.cayden.thread813;

/**
 * @author 崔冉
 * @version 1.0.0
 * @desc
 */
public class TestDeadLock {
	static final ClassA classA=new ClassA();
	static final ClassB classB=new ClassB();
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread threada=new Thread("ThreadA")
		{
			public void run(){
				classA.method1();
			}
		};
		
		Thread threadb=new Thread("ThreadB")
		{
			public void run(){
				classB.method2();
			}
		};
		threada.start();
		threadb.start();
	}

}
class ClassA{
	public static synchronized void method1 () {
		ClassB.method2();
	}
}
class ClassB{
	public static synchronized void method2 () {
		ClassA.method1();
	}
}










同步锁后的代码:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: