天天看点

J2SE(11)之多线程(死锁)1、死锁情况演示2、生产者消费者模式3、任务调度Timer

1、死锁情况演示

在多线程中,过多的同步可能会造成死锁。下面以  “一手给钱,一手给货"   为例,创建两个线程类,都拥有相同的对象作为锁对象,显示死锁情况

1.1 线程类1

public class Test implements Runnable{
	Object goods ;
	Object money ;
	
	public Test(Object goods, Object money) {
		super();
		this.goods = goods;
		this.money = money;
	}

	@Override
	public void run() {
		while(true){
			test();
		}
	}	
	public void test(){
		synchronized(goods){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized(money){
				
			}
		}
		System.out.println("一手给钱");
	}	
}
           

1.2 线程类2

public class Test2  implements Runnable{
	Object goods ;
	Object money ;
	public Test2(Object goods, Object money) {
		super();
		this.goods = goods;
		this.money = money;
	}
	@Override
	public void run() {
		while(true){
			test();
		}
	}	
	public void test(){
		synchronized(money){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized(goods){
				
			}
			
		}
		System.out.println("一手给货");
	}	
}
           

1.3 测试

public class SynDemo03 {
	public static void main(String[] args) {
        //创建共享的两个锁
		Object g =new Object();
		Object m = new Object();

		Test t1 =new Test(g,m);
		Test2 t2 = new Test2(g,m);
		Thread proxy = new Thread(t1);
		Thread proxy2 = new Thread(t2);
		proxy.start();
		proxy2.start();
	}
}
           

2、生产者消费者模式

       当多个线程共享一份资源的时候,会发生死锁的现象,我们一般是通过生产者与消费者模式进行解决。也有称为信号灯法。代码展示如下: 

2.1 共享资料电影类:

/**
 一个场景,共同的资源
  生产者消费者模式 信号灯法
 wait() :等待,释放锁   sleep 不释放锁
 notify()/notifyAll():唤醒
  与 synchronized一起使用
 */
public class Movie {
	private String pic ;
	//信号灯
	//flag -->T 生产生产,消费者等待 ,生产完成后通知消费
	//flag -->F 消费者消费 生产者等待, 消费完成后通知生产
	private boolean flag =true;
	/**
	 * 播放
	 */
	public synchronized void play(String pic){
		if(!flag){ //生产者等待
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//开始生产
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("生产了:"+pic);
		//生产完毕		
		this.pic =pic;
		//通知消费
		this.notify();
		//生产者停下
		this.flag =false;
	}
	
	public synchronized void watch(){
		if(flag){ //消费者等待
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//开始消费
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("消费了"+pic);
		//消费完毕
		//通知生产
		this.notifyAll();
		//消费停止
		this.flag=true;
	}
}
           

2.2 生产者

/**
 * 生产者
 */
public class Player implements Runnable {
	private Movie m ;
	
	public Player(Movie m) {
		super();
		this.m = m;
	}

	@Override
	public void run() {
		for(int i=0;i<20;i++){
			if(0==i%2){
				m.play("左青龙");
			}else{
				m.play("右白虎");
			}
		}
	}
}
           

2.3 消费者

public class Watcher implements Runnable {
	private Movie m ;
	
	public Watcher(Movie m) {
		super();
		this.m = m;
	}

	@Override
	public void run() {
		for(int i=0;i<20;i++){
			m.watch();
		}
	}
}
           

2.4 测试

public class App {
	public static void main(String[] args) {
		//共同的资源
		Movie m = new Movie();
		
		//多线程
		Player p = new Player(m);
		Watcher w = new Watcher(m);
		
		new Thread(p).start();		
		new Thread(w).start();
	}
}
           

2.5 馒头案例的代码如下:

public class TestProduce {
	public static void main(String[] args) {
		SyncStack sStack = new SyncStack();
		Shengchan sc = new Shengchan(sStack);
		Xiaofei xf = new Xiaofei(sStack);
		sc.start();
		xf.start();
	}
}

class Mantou {
	int id;
	Mantou(int id){
		this.id=id;
	}
}

class SyncStack{
	int index=0;
	Mantou[] ms = new Mantou[10];
	
	public synchronized void push(Mantou m){
		while(index==ms.length){
			try {
				this.wait(); 
				//wait后,线程会将持有的锁释放。sleep是即使睡着也持有互斥锁。
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify(); //唤醒在当前对象等待池中等待的第一个线程。notifyAll叫醒所有在当前对象等待池中等待的所有线程。
		//如果不唤醒的话。以后这两个线程都会进入等待线程,没有人唤醒。
		ms[index]=m;
		index++;
	}
	public synchronized Mantou pop(){
		while(index==0){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify();
		index--;
		return ms[index];
	}
}

class Shengchan extends Thread{
	SyncStack ss = null;
	
	public Shengchan(SyncStack ss) {
		this.ss=ss;
	}
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			System.out.println("造馒头:"+i);
			Mantou m = new Mantou(i);
			ss.push(m);
		}
	}
}

class Xiaofei extends Thread{
	SyncStack ss = null;
	
	public Xiaofei(SyncStack ss) {
		this.ss=ss;
	}
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			Mantou m = ss.pop();
			System.out.println("吃馒头:"+i);
			
		}
	}
}
           

3、任务调度Timer

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
    了解
  Timer() 
  schedule(TimerTask task, Date time) 
  schedule(TimerTask task, Date firstTime, long period) 
  自学 quartz
 */
public class TimeDemo01 {

	public static void main(String[] args) {
		Timer timer =new Timer();
		timer.schedule(new TimerTask(){

			@Override
			public void run() {
				System.out.println("so easy....");
			}}, new Date(System.currentTimeMillis()+1000), 200);
	}
}