葵恩的学习笔记

导航

多线程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 }
MyStack.java
 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 }
ProducerThread.java
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();
            }
        }
    }
    

}
ConsumerThread.java
 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 }
Test

 

posted on 2021-02-07 10:54  葵恩  阅读(46)  评论(0)    收藏  举报