一、死锁
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内存,线程开的越多,消耗的内存也就越大,最后死机)