您的位置:首页 > 其它

多线程__【线程安全】【线程同步】【单例模式的线程安全】【线程死锁】

2013-12-06 16:37 246 查看

线程安全问题

线程安全问题产生的原因:多条线程代码操作共享数据,一条线程还未执行完,并对结果进行反馈;其他的线程通过条件判断参与进运算,对数据重复操作

多次启动一个线程是非法的,尤其是线程已经结束后,不能重新启动

买票示例

/*卖票示例

*/
class Ticket implements Runnable
{
	private int num = 100;

	public void sale()
	{
		while (true)//
		{
			if (num>0)
			{
				try//使用sleep方法时会出现异常,继承的接口没有继承Exception 异常,所以run方法不能throws,只能try catch
				{
					Thread.sleep(10);//线程休眠10毫秒
				}
				catch (InterruptedException e)
				{
				}
				System.out.println("name: "+Thread.currentThread().getName()+"....."+num--);
			}
		}
	}
	public void run()
	{
		sale();
	}
}

class  TicketDemo
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();
		
		Thread t1= new Thread(t);
		Thread t2= new Thread(t);	
		Thread t3= new Thread(t);	
		Thread t4= new Thread(t);	
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}


运行结果出现负数票



解决方法:

当前线程执行完毕后,其它线程才能参与运算。

将共享数据的代码封装起来,当有线程在执行这些代码的时候。其它线程不可以参与运算,使用

线程同步

class Ticket implements Runnable
{
	private int num = 100;
	Object obj =new Object();

	public synchronized void sale()//同步函数,不能直接调用,因为一个线程进入后全部执行完才出来,其它线程没有锁所以执行不到
	{
		while (true)
		{
		//	synchronized(obj)//同步代码块,同步锁;需要传入对象,可以是任意对象,作为自定义锁
		//	{
				if (num>0)
				{
					try
					{
						Thread.sleep(10);//线程休眠10毫秒
					}
					catch (InterruptedException e)
					{
					}
					System.out.println("name: "+Thread.currentThread().getName()+"....."+num--);
				}
		//	}	
		}
	}
	public void run()//所有线程都可以调用run方法,在run方法中间接调用同步函数,从而间接执行到sale();
	{
		sale();
	}
}


对象如同同步就相当于一个保险箱,持有锁的线程可以进入同步中执行,没有锁的线程即使获取cpu执行权,也无法进去执行

经典实例----火车上的卫生间

同步的前提:多个线程使用同一个锁,必须保证同步中只有一个线程在执行

同步的弊端:多个线程需要判断锁,较为消耗资源

同步的原则:明确哪些代码是多线程运行代码;明确共享数据;明确多线程运行代码哪些是操作共享数据的,只能有一个共同的锁



同步的方式

①同步代码块

synchronized(对象){需要被同步的代码}//只需要把需要同步的代码封装在同步中,同步代码块的锁是传入的对象,可以是任意对象,自定义锁。

②同步函数

同步函数的锁:函数需要被对象调用,那么函数都有一个所属对象的引用,就是this。即当前任务对象

(考点)静态同步函数使用的锁是该方法所在类的字节码文件对象,类名.class

静态成员进内存的过程:内存中没有本类对象,但是一定有该类对应的字节码文件对象,类名.class,该对象的类型是class

总结:同步函数中,那个对象调用了同步,同步锁就是该对象的引用



单例模式的线程安全问题

懒汉式特点:对象延迟加载,多线程访问时存在安全隐患;可以加同步来解决。同步过程中判断锁会降低效率,而同步函数每一条线程访问都会有判断锁的过程;使用同步代码块二次判断,用判断变量来替代判断锁,只需判断一次锁,稍微提高了执行效率

由于是静态同步,所以懒汉式中的同步锁是本类对象的字节码文件

//饿汉式
class Single
{
	private static final Single s=new Single();//有final修饰
	private Single(){}
	public static Single getInstance()
	{
		return s;
	}
}

//懒汉式
class Single
{
	private static Single s =null;//无final修饰
	private Single(){}

//	public static Single getInstance()//延迟加载,多个线程并发访问时可能引发安全问题
//	public static synchronized Single getInstance()使用同步函数,多了一步判断锁的过程,多线程时较为低效
	public static Single getInstance()	//使用同步代码块
	{
		if (s==null)//减少判断锁的次数,稍微提高效率
		{
			synchronized(Single.class)//静态同步的锁
			{
				if(s==null)
					s=new Single();	
			}
				return s;
		}
	}
}


线程死锁

死锁的条件:同步中嵌套同步,同步之间的调用,由于每个同步只有一个对应的锁,相互嵌套时同时持有两个锁才会执行,一旦两个同步都持有一个对方的锁无法执行也无法释放,就会导致线程死锁。这种情况应避免发生

死锁示例:

class Test implements Runnable
{
	private boolean flag;
	Test(boolean flag)
	{
		this.flag = flag;
	}

	public void run()
	{
		if (flag)
		{
			synchronized(MyLock.a)
			{
				System.out.println("if.....a");
				synchronized(MyLock.b)
				{
					System.out.println("if....b");
				}
			}
		}
		else
		{
			synchronized(MyLock.b)
			{
				System.out.println("else....b");
				synchronized(MyLock.a)
				{
					System.out.println("else......a");
				}
			}
		}
	}
}

class MyLock
{
	static Object a= new Object();
	static Object b= new Object();
}

class DeadLock 
{
	public static void main(String[] args) 
	{
		Thread t1=new Thread(new Test(true));
		Thread t2=new Thread(new Test(false));
		t1.start();
		t2.start();
	}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: