一、死锁现象:

          两个或者两个以上的线程再争夺资源的过程中,发生的一种相互等待的现象

案例:

class MyClock{
	//创建锁对象
	public static final Object objA = new Object();
	public static final Object objB = new Object();
}
class DieLock extends Thread{
	private boolean flag;
	
	public DieLock(boolean flag) {
		this.flag = flag;
	}
	
	@Override
	public void run() {
		if(flag) {
			//同步嵌套
			synchronized (MyClock.objA) {
				System.out.println("if里的objA");
				synchronized (MyClock.objB) {
					System.out.println("if里的objB");
				}
			}
		}else {
			synchronized (MyClock.objB) {
				System.out.println("else里的objB");
				synchronized (MyClock.objA) {
					System.out.println("else里的objA");
				}
			}
		}
	}
}
public class DieLockDemo {
	public static void main(String[] args) {
		DieLock d1 = new DieLock(true);
		DieLock d2 = new DieLock(false);
		
		d1.start();
		d2.start();
	}
}

二、线程间的通信问题:

       不同种类的线程间针对同一资源的操作

       就像生产者生产出的西瓜供消费者消费,生产者和消费者都对西瓜进行了操作,这就实现了生产者和消费者之间的通信

线程对同一学生类进行操作:

package Demo;
//创建学生类
class Student {
	
	public String name;
	public int age;
}
//给学生类赋值(生产者)
class SetThread implements Runnable {
	Student s;
	public SetThread(Student s) {
		this.s = s;
	}
	int x = 0;
	@Override
	public void run() {
		while(true) {
			synchronized (s) {
				if(x % 2 == 0) {
					s.name = "lyr";
					s.age = 18;
				}else {
					s.name = "kx";
					s.age = 20;
				}
				x++;
			}
		}
		
	}

}
//输出学生类的值(消费者)
class GetThread implements Runnable {
	Student s;
	public GetThread(Student s) {
		this.s = s;
	}
	@Override
	public void run() {
		while(true) {
			synchronized (s) {
				System.out.println(s.name+"---"+s.age);
			}
			
		}
	}

}

public class StudentDemo {
	public static void main(String[] args) {
		Student s = new Student();
		SetThread st = new SetThread(s);
		GetThread gt = new GetThread(s);
		
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(gt);
		
		t1.start();
		t2.start();
	}
}

但是这种生产者会一直产生数据,不管消费者是否已经使用

正常的操作:

       生产者:

                先看是否有数据,有就等待,没有就生产

      消费者:

                先看是否有数据,有就使用,没有就等待

如何实现:

       通过Java提供的等待唤醒机制

Object类提供了三个方法:

      wait():等待

      notify:唤醒单个线程

      notifyall:唤醒全部线程

改进后的代码:

package Demo;
//创建学生类
class Student {
	
	private String name;
	private int age;
	private boolean flag;
	
	public synchronized void set(String name,int age) {
		if(this.flag) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		this.name = name;
		this.age = age;
		
		this.flag = true;
		this.notify();
	}
	
	public synchronized void get() {
		if(!this.flag) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		System.out.println(this.name + "----" + this.age);
		
		this.flag = false;
		this.notify();
	}
}
//给学生类赋值
class SetThread implements Runnable {
	Student s;
	public SetThread(Student s) {
		this.s = s;
	}
	int x = 0;
	@Override
	public void run() {
		while(true) {
			if(x % 2 == 0) {
				s.set("lyr", 18);
			}else {
				s.set("kx", 20);
			}
			x++;
		 }
	}
}
//输出学生类的值
class GetThread implements Runnable {
	Student s;
	public GetThread(Student s) {
		this.s = s;
	}
	@Override
	public void run() {
		while(true) {
			s.get();
		}
	}
}

public class StudentDemo {
	public static void main(String[] args) {
		Student s = new Student();
		SetThread st = new SetThread(s);
		GetThread gt = new GetThread(s);
		
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(gt);
		
		t1.start();
		t2.start();
	}
}

三、线程池:

1、线程池的好处:

      线程池里的每一个线程代码结束后,并不会死亡,而是回到线程池中成为空闲状态,等待下一个对象来使用

线程池的使用:

package Demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class MyRunnable implements Runnable{

	@Override
	public void run() {
		for(int x = 0;x < 100;x ++) {
		System.out.println(Thread.currentThread().getName() + ":" + x);
		}
	}
	
}
public class ThreadPoolDemo {
	public static void main(String[] args) {
		ExecutorService pool = Executors.newFixedThreadPool(2);
		
		pool.submit(new MyRunnable());
		pool.submit(new MyRunnable());
		
		pool.shutdown();
	}
}

四、Callable实现多线程:

Callable:带泛型的接口

                依赖线程池实现多线程,所以有局限性

package Demo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class MyCallable implements Callable{

	@Override
	public Object call() throws Exception {
		for(int x= 0;x < 100 ; x ++) {
			System.out.println(Thread.currentThread().getName()+":"+x);
		}
		return null;
	}
	
}
public class CallableDemo {
	public static void main(String[] args) {
		ExecutorService pool = Executors.newFixedThreadPool(2);
		
		pool.submit(new MyCallable());
		pool.submit(new MyCallable());
		
		pool.shutdown();
	}
}