死锁 : 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法往下执行。 此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程 原理 :  某个线程执行完成,需要先后嵌套锁定两个对象,在这个过程中,先锁定了第一个对象 另一个线程执行完成也需要先后嵌套锁定两个对象,在这个过程中,先锁定了第二个对象 第一个线程执行中,要执行到第二个对象的时候,发现第二个对象被锁定,进入等待状态,等待交出锁 第二个线程执行中,要执行到第一个对象的时候,发现第一个对象也被锁定,也进入等待状态 此时两个线程都在等待对方交出锁,导致死锁  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执行完成" ) ; } 
} 
Object中的方法 wait : 让当前线程进入等待状态(挂起),并释放锁,当被唤醒之后,接着挂起的位置继续执行,假如之前执行了1、2,到3挂起,那么被唤醒后接着执行3 notify : 唤醒一个在该对象中挂起的任意一个线程 notifyAll : 唤醒在该对象中挂起的所有 线程 这几个方法必须出现在加锁的成员方法 中 wait : 如果是无参,则不会自动醒,也可以传入long类型的值,代表毫秒数,多久之后自动醒 wait 和 sleep的区别 :  sleep : 让当前线程进入睡眠状态, 是静态方法,和是否加锁没有关系,如果在加锁的方法中,也不会释放锁  wait : 让当前线程进入挂起等待状态,必须在加锁的成员方法中,另外会释放锁   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 ( ) ; } } 
} 
 
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内存,线程开的越多,消耗的内存也就越大,最后死机)