Part1、生产消费关系
-------------------------------------
1.容器加上限:库存超过一定数量,不再生产。
2.生产消费互斥:同一时间只能有一个人访问库存。
Part2、等待 -- 通知模式 (wait --- notify)
-------------------------------------
1.wait():让当前线程等待,将线程加入到锁对象等待区,同时释放锁
2.notify():唤醒线程,在等待区随机唤醒一个线程,注意是随机的,但是不会释放锁,不会操作锁
3.sleep():仅仅是放弃CPU的抢占权,与锁无关
4.wait和notify虽然是object的方法,但是必须在线程,在synchonized中才能起作用
5.当等待区线程被唤醒,会立刻执行wait之后的代码
6.wait 和 notify 方法,是当前锁对象的方法,必须是当前锁对象调用,注意一致性
Part3、死锁
-------------------------------------------
1.一个锁的时候,所有的线程都进入了等待队列,死锁
2.多个锁的时候,无锁可用,死锁
3.解决死锁方法1:wait(int n),最多等待n毫秒,期间可以被唤醒
4.解决死锁方法2:notifyAll()方法,通知等待队列中的所有等待线程,可以去抢锁抢CPU了
Part1,2,3 代码示例:
public class Ts01 { public static void main(String[] args) { MyList list = new MyList(); Product p = new Product(list); Product p1 = new Product(list); Product p2 = new Product(list); Customer c = new Customer(list); p.start(); p1.start(); p2.start(); c.start(); } } class MyList { private List<Integer> list = new ArrayList<Integer>(); private int MAX = 1; // 添加 public synchronized void add(Integer i) { //如果仓库已满,就释放锁,并且进入等待区 //如果被唤醒,立刻执行wait之后代码,即进入循环继续判断仓库是否已经满 while (list.size() >= MAX) { try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //仓库未满,开始生产 list.add(i); System.out.println("库存" + list.size()); //生产完毕,通知等待区,随机唤醒一个线程(如果唤醒的是生产线程,那么继续唤醒) //直到唤醒消费线程 notify(); } // 取出 public synchronized Integer remove() { //如果仓库为空,则进入等待区等待 //如果被唤醒,接着wait执行,继续判断仓库是否为空 while(list.isEmpty()) { try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //仓库不为空,开始消费 Integer i = list.remove(0); //消费完毕,通知,唤醒等待区的随机线程。如果唤醒的是消费线程,那么继续唤醒 //直到唤醒生产线程 notify(); return i; } // 判空 public boolean isEmpty() { return list.isEmpty(); } } // 生产者 class Product extends Thread { private MyList list = null; static int i = 1; public Product(MyList list) { this.list = list; } public void run() { while (true) { list.add(i); System.out.println("增加了" + i); i++; } } } // 消费者 class Customer extends Thread { private MyList list = null; public Customer(MyList list) { this.list = list; } public void run() { while (true) { try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Integer in = list.remove(); if (in != null) System.out.println("移除" + in); } } }
Part4、线程属性和方法
---------------------------------------
1.Thread.currentThread():静态方法,获取当前执行的线程
2.setName()/getName():非静态方法,设定/获取线程名称
3.setPriority(1~10)/getPriority():设定/查看线程优先级
Part5、开启线程的另外一种方式:实现Runnable接口
---------------------------------------
1.定义接口Runnable的实现类MyRunnable
2.在实现类中重写方法run();
3.创建MyRunnable的实例 r
4.创建线程的时候,传入参数r:new Thread(r);
5.调用线程的start方法,开启线程
Part6、Runnable的好处
---------------------------------------
1.因为Runnable是接口,所以避免了Java单继承的局限性
2.接口降低耦合
Part7、线程的状态
---------------------------------------
1.BLOCKED //阻塞
2.NEW //新建
3.RUNNABLE //执行中
4.TERMTNATED //已终止
5.TIME_WAITING //限时等待
6.WAITING //等待
Part4,5,6,7 代码示例
public class Ts03 { public static void main(String[] args) { //Thread t = Thread.currentThread(); //System.out.println(t.getName()); //t.setPriority(newPriority) //System.out.println(t.getPriority()); MyRunnable r = new MyRunnable(); new Thread(r).start(); } } class MyRunnable implements Runnable { @Override public void run() { while(true) { System.out.println("HelloWorld"); } } } public class Ts03 { public static void main(String[] args) { //Thread t = Thread.currentThread(); //System.out.println(t.getName()); //t.setPriority(newPriority) //System.out.println(t.getPriority()); MyRunnable r = new MyRunnable(); new Thread(r).start(); } } class MyRunnable implements Runnable { @Override public void run() { while(true) { System.out.println("HelloWorld"); } } }
Part8、熊吃蜂蜜问题
-------------------------------------------------------
100只蜜蜂.
每只蜜蜂一次生产蜂蜜量为1.
蜜罐的容量是20.
熊在蜜罐满了的时候一次性吃掉所有蜂蜜。
提示:蜜蜂生产蜂蜜时,如果蜜罐已满则等待,否则+1,notifyAll.
熊吃蜂蜜时,如果蜜罐已满则吃掉再notifyAll,否则,notifyAll.
Part9、和尚吃馒头问题
--------------------------------------------------------
100馒头
50个和尚,每个和尚一次只能吃一个馒头,但是最多只允许吃三个馒头。
看每个和尚各吃了多少馒头。
Part8,9代码示例
public class Ts02 { public static void main(String[] args) { // //蜂蜜罐 // Jar jar = new Jar(); // //熊 // for (int i = 0; i < 2; i++) { // new Thread(new Bear(jar)).start(); // } // //蜜蜂 // for (int i = 0; i < 100; i++) { // new Thread(new Bee(jar)).start(); // } ManTouGuo m = new ManTouGuo(); for (int i = 0; i < 50; i++) { new Thread(new Monk(m)).start(); } } } //--------------------练习1---------------------------// /* * 1.熊吃蜂蜜问题 100只蜜蜂. 每只蜜蜂一次生产蜂蜜量为1. 蜜罐的容量是20. 熊在蜜罐满了的时候一次性吃掉所有蜂蜜。 提示:蜜蜂生产蜂蜜时,如果蜜罐已满则等待,否则+1,notifyAll. 熊吃蜂蜜时,如果蜜罐已满则吃掉再notifyAll,否则,notifyAll. */ class Jar{ //罐子最大蜂蜜量 public static final int MAX = 20; //罐子当前蜂蜜量 public int count = 0; //增加蜂蜜 public synchronized void add(){ //超过20.停止生产 while(count >= MAX){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //开始生产 count ++; System.out.println("库存" + count); //通知所有等待线程工作 notifyAll(); } //吃蜂蜜 public synchronized void eat(){ //小于20,等待 while(count <20) { try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //吃蜂蜜 count = count - 20; //通知 notifyAll(); } } class Bee implements Runnable{ Jar jar; public Bee(Jar jar){ this.jar = jar; } @Override public void run() { while(true){ jar.add(); System.out.println("蜜蜂产密,剩余" + jar.count); } } } class Bear implements Runnable{ Jar jar; public Bear(Jar jar){ this.jar = jar; } @Override public void run() { while(true){ jar.eat(); System.out.println("熊吃蜂蜜,蜂蜜剩余" + jar.count); } } } //------------------------练习2-----------------------// /* * 2.和尚吃馒头问题 100馒头 50个和尚,每个和尚一次只能吃一个馒头,但是最多只允许吃三个馒头。 看每个和尚各吃了多少馒头。 */ //馒头锅 class ManTouGuo { //剩余馒头总数 public int remainMTCount = 100; //吃馒头 public synchronized void eat() { if(remainMTCount > 0) { remainMTCount --; System.out.println("被吃了一个,剩余" + remainMTCount + "个馒头!"); } } } //和尚 class Monk implements Runnable { //吃了多少个 int eatCount = 0; //馒头锅 ManTouGuo mtg; public Monk(ManTouGuo mtg) { this.mtg = mtg; } @Override public void run() { while( eatCount < 3 && mtg.remainMTCount >0 ) { mtg.eat(); eatCount++; } System.out.println("我吃了" + eatCount + "个馒头!"); } }
本文完!