一、死锁  
 1.概述  
死锁 : 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法往下执行。 此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程 原理 :  
  某个线程执行完成,需要先后嵌套锁定两个对象,在这个过程中,先锁定了第一个对象 另一个线程执行完成也需要先后嵌套锁定两个对象,在这个过程中,先锁定了第二个对象 第一个线程执行中,要执行到第二个对象的时候,发现第二个对象被锁定,进入等待状态,等待交出锁 第二个线程执行中,要执行到第一个对象的时候,发现第一个对象也被锁定,也进入等待状态 此时两个线程都在等待对方交出锁,导致死锁      
 2.代码实现  
public  class  Thread_01_DeadLock  { 
	public  static  void  main ( String [ ]  args)  { 
		Object  o1= new  Object ( ) ; 
		Object  o2= new  Object ( ) ; 
		Thread  t1= new  Thread ( new  T1 ( o1,  o2) ) ; 
		Thread  t2= new  Thread ( new  T2 ( o1,  o2) ) ; 
		t1. start ( ) ; 
		t2. start ( ) ; 
	} 
} 
class  T1 implements  Runnable { 
	Object  o1; 
	Object  o2; 
	public  T1 ( Object  o1, Object  o2) { 
		this . o1= o1; 
		this . o2= o2; 
	} 
	@Override 
	public  void  run ( )  { 
		synchronized  ( o1)  { 
			System . out. println ( Thread . currentThread ( ) . getName ( ) + "-->T1o1已锁定" ) ; 
			synchronized  ( o2)  { 
				System . out. println ( Thread . currentThread ( ) . getName ( ) + "-->T1o2已锁定" ) ; 
			} 
		} 
		System . out. println ( "t1执行完成" ) ; 
	} 
} 
class  T2 implements  Runnable { 
	Object  o1; 
	Object  o2; 
	public  T2 ( Object  o1, Object  o2) { 
		this . o1= o1; 
		this . o2= o2; 
	} 
	@Override 
	public  void  run ( )  { 
		try  { 
			Thread . sleep ( 1000 ) ; 
		}  catch  ( InterruptedException  e)  { 
			e. printStackTrace ( ) ; 
		} 
		synchronized  ( o2)  { 
			System . out. println ( Thread . currentThread ( ) . getName ( ) + "-->T2o2已锁定" ) ; 
			synchronized  ( o1)  { 
				System . out. println ( Thread . currentThread ( ) . getName ( ) + "-->T2o1已锁定" ) ; 
			} 
		} 
		System . out. println ( "t2执行完成" ) ; 
	} 
} 
  
 二、线程通信  
 1.概述  
Object中的方法 wait : 让当前线程进入等待状态(挂起),并释放锁,当被唤醒之后,接着挂起的位置继续执行,假如之前执行了1、2,到3挂起,那么被唤醒后接着执行3 notify : 唤醒一个在该对象中挂起的任意一个线程 notifyAll : 唤醒在该对象中挂起的所有 线程 这几个方法必须出现在加锁的成员方法 中 wait : 如果是无参,则不会自动醒,也可以传入long类型的值,代表毫秒数,多久之后自动醒 wait 和 sleep的区别 :  
  sleep : 让当前线程进入睡眠状态, 是静态方法,和是否加锁没有关系,如果在加锁的方法中,也不会释放锁  wait : 让当前线程进入挂起等待状态,必须在加锁的成员方法中,另外会释放锁       
 2.使用方式  
public  class  Thread_03_Wait  { 
	public  static  void  main ( String [ ]  args)  throws  InterruptedException  { 
		Num  num= new  Num ( ) ; 
		Thread  t1= new  PrintNum ( num) ; 
		Thread  t2= new  PrintNum ( num) ; 
		t1. start ( ) ; 
		Thread . sleep ( 10 ) ; 
		t2. start ( ) ; 
	} 
} 
class  PrintNum  extends  Thread { 
	Num  num; 
	public  PrintNum ( Num  num) { 
		this . num= num; 
	} 
	@Override 
	public  void  run ( )  { 
		while  ( true )  { 
			num. printNums ( ) ; 
		} 
	} 
} 
class  Num { 
	private  int  count = 1 ; 
	public  synchronized  void  printNums ( ) { 
		System . out. println ( Thread . currentThread ( ) . getName ( ) + "-->" + count) ; 
		count++ ; 
		
		this . notifyAll ( ) ; 
		try  { 
			Thread . sleep ( 1000 ) ; 
			
			this . wait ( ) ; 
		}  catch  ( InterruptedException  e)  { 
			e. printStackTrace ( ) ; 
		} 
	} 
} 
  
 3.生产者消费者  
 
 3.1.示例  
public  class  Thread_04_Producer  { 
	public  static  void  main ( String [ ]  args)  { 
		SynStack  ss= new  SynStack ( ) ; 
		Thread  producer1= new  Thread ( new  Producer ( ss) ) ; 
		Thread  producer2= new  Thread ( new  Producer ( ss) ) ; 
		Thread  consumer1= new  Thread ( new  Consumer ( ss) ) ; 
		Thread  consumer2= new  Thread ( new  Consumer ( ss) ) ; 
		producer1. start ( ) ; 
		producer2. start ( ) ; 
		consumer1. start ( ) ; 
		consumer2. start ( ) ; 
	} 
} 
class  Producer  implements  Runnable { 
	private  SynStack  ss; 
	public  Producer ( SynStack  ss) { 
		this . ss= ss; 
	} 
	@Override 
	public  void  run ( )  { 
		for  ( int  i =  0 ;  i <  26 ;  i++ )  { 
			ss. push ( ( char ) ( 'a' + i) ) ; 
		} 
	} 
} 
class  Consumer  implements  Runnable { 
	private  SynStack  ss; 
	public  Consumer ( SynStack  ss) { 
		this . ss= ss; 
	} 
	@Override 
	public  void  run ( )  { 
		for  ( int  i =  0 ;  i <  26 ;  i++ )  { 
			ss. pop ( ) ; 
			try  { 
				Thread . sleep ( 100 ) ; 
			}  catch  ( InterruptedException  e)  { 
				e. printStackTrace ( ) ; 
			} 
		} 
	} 
} 
class  SynStack { 
	int  count= 0 ; 
	char [ ]  data= new  char [ 6 ] ; 
	
	public  synchronized  void  push ( char  ch) { 
		
		while ( count == data. length) { 
			try  { 
				this . wait ( ) ; 
			}  catch  ( InterruptedException  e)  { 
				e. printStackTrace ( ) ; 
			} 
		} 
		
		if  ( count== 0 )  { 
			this . notifyAll ( ) ; 
		} 
		data[ count++ ] = ch; 
		System . out. println ( Thread . currentThread ( ) . getName ( ) + "生产了 " + ch+ " 还剩 " + count+ " 个货物" ) ; 
	} 
	
	public  synchronized  char  pop ( ) { 
		
		while ( count == 0 ) { 
			try  { 
				this . wait ( ) ; 
			}  catch  ( InterruptedException  e)  { 
				e. printStackTrace ( ) ; 
			} 
		} 
		
		if  ( count== data. length)  { 
			this . notifyAll ( ) ; 
		} 
		char  ch= data[ -- count] ; 
		System . out. println ( Thread . currentThread ( ) . getName ( ) + "消费了 " + ch+ " 还剩 " + count+ " 个货物" ) ; 
		return  ch; 
	} 
} 
  
 三、单例模式  
public  class  SingLeton  { 
	private  SingLeton ( ) { 
		
	} 
	
	private  volatile  static  SingLeton  singLeton; 
	public  static  SingLeton  getInstance ( ) { 
        
		if  ( singLeton== null )  { 
            
			synchronized  ( SingLeton . class )  { 
				if  ( singLeton== null )  { 
                    
					singLeton= new  SingLeton ( ) ; 
				} 	
			} 
		} 
		return  singLeton; 
	} 
} 
  
 四、线程池  
线程池的作用:  
    根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果; 少了浪费了系统资源,多了造成系统拥挤效率不高。 用线程池控制线程数量,其他线程排队等候。 一个任务执行完毕,再从队列的中取最前面的任务开始执行。 若队列中没有等待进程,线程池的这一资源处于等待。 当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了,否则进入等待队列。 为什么要用线程池:  
  减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)