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