多线程2
一、死锁
死锁需要满足四个条件: 1、互斥条件; 2、请求与保持条件; 3、循环等待条件; 4、不可剥夺条件
二、线程交互
使用wait和notify进行线程交互
wait的作用是使编程等待,并临时释放资源占有。
notify的作用是通知那些在等待的线程可以苏醒过来了。
三、练习:生产者消费者问题
生产者消费者问题是一个非常典型性的线程交互的问题。
1. 使用栈来存放数据
1.1 把栈改造为支持线程安全
1.2 把栈的边界操作进行处理,当栈里的数据是0的时候,访问pull的线程就会等待。 当栈里的数据是200的时候,访问push的线程就会等待
2. 提供一个生产者(Producer)线程类,生产随机大写字符压入到堆栈
3. 提供一个消费者(Consumer)线程类,从堆栈中弹出字符并打印到控制台
4. 提供一个测试类,使两个生产者和三个消费者线程同时运行,结果类似如下 :
四、锁lock
Lock lock = new ReentrantLock();//Lock是一个借口,为了使用一个Lock对象,需要用到该声明。
1. Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,Lock是代码层面的实现。
2. Lock可以选择性的获取锁,如果一段时间获取不到,可以放弃。synchronized不行,会一根筋一直获取下去。 借助Lock的这个特性,就能够规避死锁,synchronized必须通过谨慎和良好的设计,才能减少死锁的发生。
3. synchronized在发生异常和同步块结束的时候,会自动释放锁。而Lock必须手动释放, 所以如果忘记了释放锁,一样会造成死锁。
1 package producer_consumer; 2 3 import java.util.LinkedList; 4 5 public class MyStack <T>{ 6 LinkedList<T> values = new LinkedList<T>(); 7 8 public synchronized void push(T t) { 9 while(values.size()>=200) { 10 try { 11 this.wait(); 12 }catch(InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 this.notifyAll(); 17 values.addLast(t); 18 } 19 20 public synchronized T pull() { 21 while(values.isEmpty()) { 22 try { 23 this.wait(); 24 }catch(InterruptedException e) { 25 e.printStackTrace(); 26 } 27 } 28 this.notifyAll(); 29 return values.removeLast(); 30 } 31 32 public T peek() { 33 return values.getLast(); 34 } 35 36 37 }
1 package producer_consumer; 2 3 public class ProducerThread extends Thread{ 4 private MyStack<Character> stack; 5 public ProducerThread(MyStack<Character>stack,String name){ 6 super(name); 7 this.stack = stack; 8 } 9 public void run() { 10 while(true) { 11 char c = randomChar(); 12 System.out.println(this.getName()+"push:"+c); 13 stack.push(c); 14 try { 15 Thread.sleep(100); 16 }catch(InterruptedException e) { 17 e.printStackTrace(); 18 } 19 } 20 } 21 public char randomChar() { 22 return(char)(Math.random()*('Z'+1-'A')+'A'); 23 } 24 25 }
package producer_consumer; public class ConsumerThread extends Thread{ private MyStack<Character> stack; public ConsumerThread(MyStack<Character> stack,String name) { super(name); this.stack =stack; } public void run() { while(true) { char c=stack.pull(); System.out.println(this.getName()+"pull:"+c); try { Thread.sleep(100); }catch(InterruptedException e) { e.printStackTrace(); } } } }
1 package producer_consumer; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 MyStack<Character> stack = new MyStack<>(); 8 new ProducerThread(stack, "Producer1").start(); 9 new ProducerThread(stack, "Producer2").start(); 10 new ConsumerThread(stack, "Consumer1").start(); 11 new ConsumerThread(stack, "Consumer2").start(); 12 new ConsumerThread(stack, "Consumer3").start(); 13 14 } 15 16 }
浙公网安备 33010602011771号