jdk Thread状态与生产者消费者模型

 

public enum State {
    /**
     * Thread state for a thread which has not yet started.
     */
    NEW,

    /**
     * Thread state for a runnable thread.  A thread in the runnable
     * state is executing in the Java virtual machine but it may
     * be waiting for other resources from the operating system
     * such as processor.
     */
    RUNNABLE,

    /**
     * Thread state for a thread blocked waiting for a monitor lock.
     * A thread in the blocked state is waiting for a monitor lock
     * to enter a synchronized block/method or
     * reenter a synchronized block/method after calling
     * {@link Object#wait() Object.wait}.
     */
    BLOCKED,

    /**
     * Thread state for a waiting thread.
     * A thread is in the waiting state due to calling one of the
     * following methods:
     * <ul>
     *   <li>{@link Object#wait() Object.wait} with no timeout</li>
     *   <li>{@link #join() Thread.join} with no timeout</li>
     *   <li>{@link LockSupport#park() LockSupport.park}</li>
     * </ul>
     *
     * <p>A thread in the waiting state is waiting for another thread to
     * perform a particular action.
     *
     * For example, a thread that has called <tt>Object.wait()</tt>
     * on an object is waiting for another thread to call
     * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
     * that object. A thread that has called <tt>Thread.join()</tt>
     * is waiting for a specified thread to terminate.
     */
    WAITING,

    /**
     * Thread state for a waiting thread with a specified waiting time.
     * A thread is in the timed waiting state due to calling one of
     * the following methods with a specified positive waiting time:
     * <ul>
     *   <li>{@link #sleep Thread.sleep}</li>
     *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
     *   <li>{@link #join(long) Thread.join} with timeout</li>
     *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
     *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
     * </ul>
     */
    TIMED_WAITING,

    /**
     * Thread state for a terminated thread.
     * The thread has completed execution.
     */
    TERMINATED;
}

1、NEW

新创建线程,还没调用start方法,此时线程处于New的状态

Thread thread= new Thread(new Runnable() {
    @Override
    public void run() {
      testConsume();
    }
});
Log.d(TAG, "onCreate1: state="+thread.getState());

此时log打印:

onCreate1: state=NEW

2、RUNNABLE

调用了start方法就可以在java虚拟机中执行了,但是可能并没有在操作系统中运行,因为此时可能缺少CPU资源。

Thread thread= new Thread(new Runnable() {
    @Override
    public void run() { 
      testConsume();
    }
});
Log.d(TAG, "onCreate1: state="+thread.getState());
thread.start();
Log.d(TAG, "onCreate2: state="+thread.getState());

此时log打印:

onCreate1: state=NEW

onCreate2: state=RUNNABLE

3、BLOCKED

进入synchronized 代码块但是没有获取到锁对象,可能是首次进入synchronized 代码块也可能是之前进入synchronized代码块使用wait等待又被唤醒再次进入synchronized代码块。

4、WAITING

由于线程调用了无时间参数的Object#wait()、Thread.join、LockSupport.park中的某个方法使得线程处于等待状态,此时线程等待其他线程的特定动作,比如Object.wait()等待其他线程调用Object.notify()或Object.notifyAll();Thread.join()等待另外的线程执行完;

5、TIMED_WAITING

等待特定时间,当调用带时间参数的这些方法Thread.sleep、Object.wait、Thread.join、LockSupport.parkNanos、LockSupport.parkUntil某个方法时进入该状态

6、TERMINATED

线程执行结束

Thread thread;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    thread= new Thread(new Runnable() {
        @Override
        public void run() {
          testConsume();
        }
    });
    Log.d(TAG, "onCreate1: state="+thread.getState());
    thread.start();
    Log.d(TAG, "onCreate2: state="+thread.getState());
}
@Override
protected void onResume() {
    super.onResume();
    Log.d(TAG, "onResume: state="+thread.getState());
}

此时log打印如下:

2021-03-01 16:20:53.311 12578-12578/com.shan.myapplication D/hahhhxxxx: onCreate1: state=NEW
2021-03-01 16:20:53.312 12578-12578/com.shan.myapplication D/hahhhxxxx: onCreate2: state=RUNNABLE
2021-03-01 16:20:53.331 12578-12578/com.shan.myapplication D/hahhhxxxx: onResume: state=TERMINATED

疑难点

(1)BLOCKED和WAITING的区别是WAITING等待某一条件,BLOCKED等待的是对象锁;

(2)BLOCKED与中断interrupt的区别:BLOCKED是线程的一个状态,interrupt用于线程自身设置一个标志位,在java中需要开发者自己根据这个标志或者InterruptedException然后执行相应的动作。在非死锁的情况下interrupt可以打断BLOCKED状态。

final Object lock1 = new Object();
Thread thread1 = new Thread() {
    public void run() {
        try {
            synchronized (lock1) {
                Thread.sleep(10000000);// 不会在这里死掉
                System.out.println(Thread.currentThread());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("InterruptedException1 e="+e.getMessage()+",thread1.state="+getState());
        }
    }
};
System.out.println("Starting thread...");
thread1.start();
Thread.sleep(3000);
System.out.println("Interrupting thread...,thread1="+thread1.getState());
thread1.interrupt(); //中断
Thread.sleep(3000);
System.out.println("Stopping application...thread1="+thread1.getState());

log打印如下

2021-03-01 19:09:44.795 16183-16221/com.shan.myapplication I/System.out: Starting thread...
2021-03-01 19:09:47.797 16183-16221/com.shan.myapplication I/System.out: Interrupting thread...,thread1=TIMED_WAITING
2021-03-01 19:09:47.805 16183-16222/com.shan.myapplication I/System.out: InterruptedException1 e=null,thread1.state=RUNNABLE
2021-03-01 19:09:50.800 16183-16221/com.shan.myapplication I/System.out: Stopping application...thread1=TERMINATED

生产者消费者模型

通过notify和wait可以创建一个生产者消费者模型

仓库类Storage

 

/**
 *  生产者和消费者的问题
 *  wait、notify/notifyAll() 实现
 */
public class Storage implements AbstractStorage {
    //仓库最大容量
    private final int MAX_SIZE = 100;
    //仓库存储的载体
    private LinkedList list = new LinkedList();

    //生产产品
    public void produce(int num){
        //同步
        synchronized (list){
            //仓库剩余的容量不足以存放即将要生产的数量,暂停生产
            while(list.size()+num > MAX_SIZE){
                System.out.println("【要生产的产品数量】:" + num + "\t【库存量】:"
                        + list.size() + "\t暂时不能执行生产任务!");

                try {
                    //条件不满足,生产阻塞
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            for(int i=0;i<num;i++){
                list.add(new Object());
            }

            System.out.println("【已经生产产品数】:" + num + "\t【现仓储量为】:" + list.size());

            list.notifyAll();
        }
    }

    //消费产品
    public void consume(int num){
        synchronized (list){

            //不满足消费条件
            while(num > list.size()){
           // if(num > list.size()){ if会导致唤醒后list.remove()异常
                System.out.println("【要消费的产品数量】:" + num + "\t【库存量】:"
                        + list.size() + "\t暂时不能执行消费任务!");

                try {
                    System.out.println("consume0");
                    list.wait();//如果通过notify或者notifyAll被唤醒,那么程序开始执行wait的下一句代码打印consume1
                    System.out.println("consume1");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("consume2");
            }
            System.out.println("开始消费产品");
            //消费条件满足,开始消费
            for(int i=0;i<num;i++){
                list.remove();
            }

            System.out.println("【已经消费产品数】:" + num + "\t【现仓储量为】:" + list.size());

            list.notifyAll();
        }
    }

生产者类

 

public class Producer extends Thread{
    //每次生产的数量
    private int num ;

    //所属的仓库
    public AbstractStorage abstractStorage;

    public Producer(AbstractStorage abstractStorage){
        this.abstractStorage = abstractStorage;
    }

    public void setNum(int num){
        this.num = num;
    }

    // 线程run函数
    @Override
    public void run()
    {
        produce(num);
    }

    // 调用仓库Storage的生产函数
    public void produce(int num)
    {
        abstractStorage.produce(num);
    }
}

消费者类

 

public class Producer extends Thread{
    //每次生产的数量
    private int num ;

    //所属的仓库
    public AbstractStorage abstractStorage;

    public Producer(AbstractStorage abstractStorage){
        this.abstractStorage = abstractStorage;
    }

    public void setNum(int num){
        this.num = num;
    }

    // 线程run函数
    @Override
    public void run()
    {
        produce(num);
    }

    // 调用仓库Storage的生产函数
    public void produce(int num)
    {
        abstractStorage.produce(num);
    }
}

抽象接口

public interface AbstractStorage {
    void consume(int num);
    void produce(int num);
}

 

测试程序

 

private void testConsume() {
    // 仓库对象
    AbstractStorage abstractStorage = new Storage();

    // 生产者对象
    Producer p1 = new Producer(abstractStorage);
    Producer p2 = new Producer(abstractStorage);
    Producer p3 = new Producer(abstractStorage);
    Producer p4 = new Producer(abstractStorage);
    Producer p5 = new Producer(abstractStorage);
    Producer p6 = new Producer(abstractStorage);
    Producer p7 = new Producer(abstractStorage);

    // 消费者对象
    Consumer c1 = new Consumer(abstractStorage);
    Consumer c2 = new Consumer(abstractStorage);
    Consumer c3 = new Consumer(abstractStorage);

    // 设置生产者产品生产数量
    p1.setNum(10);
    p2.setNum(10);
    p3.setNum(10);
    p4.setNum(10);
    p5.setNum(10);
    p6.setNum(10);
    p7.setNum(80);

    // 设置消费者产品消费数量
    c1.setNum(50);
    c2.setNum(20);
    c3.setNum(30);

    // 线程开始执行
    c1.start();
    c2.start();
    c3.start();

    p1.start();
    p2.start();
    p3.start();
    p4.start();
    p5.start();
    p6.start();
    p7.start();
}

log打印如下

 

2021-03-02 09:54:57.505 13063-13110/com.shan.myapplication I/System.out: 【要消费的产品数量】:50	【库存量】:0	暂时不能执行消费任务!
2021-03-02 09:54:57.505 13063-13110/com.shan.myapplication I/System.out: consume0
2021-03-02 09:54:57.506 13063-13115/com.shan.myapplication I/System.out: 【已经生产产品数】:10	【现仓储量为】:10
2021-03-02 09:54:57.507 13063-13117/com.shan.myapplication I/System.out: 【已经生产产品数】:10	【现仓储量为】:20
2021-03-02 09:54:57.507 13063-13113/com.shan.myapplication I/System.out: 【已经生产产品数】:10	【现仓储量为】:30
2021-03-02 09:54:57.508 13063-13112/com.shan.myapplication I/System.out: 开始消费产品
2021-03-02 09:54:57.508 13063-13112/com.shan.myapplication I/System.out: 【已经消费产品数】:30	【现仓储量为】:0
2021-03-02 09:54:57.509 13063-13114/com.shan.myapplication I/System.out: 【已经生产产品数】:10	【现仓储量为】:10
2021-03-02 09:54:57.510 13063-13111/com.shan.myapplication I/System.out: 【要消费的产品数量】:20	【库存量】:10	暂时不能执行消费任务!
2021-03-02 09:54:57.510 13063-13111/com.shan.myapplication I/System.out: consume0
2021-03-02 09:54:57.512 13063-13116/com.shan.myapplication I/System.out: 【已经生产产品数】:10	【现仓储量为】:20
2021-03-02 09:54:57.512 13063-13111/com.shan.myapplication I/System.out: consume1
2021-03-02 09:54:57.512 13063-13111/com.shan.myapplication I/System.out: consume2
2021-03-02 09:54:57.513 13063-13111/com.shan.myapplication I/System.out: 开始消费产品
2021-03-02 09:54:57.513 13063-13111/com.shan.myapplication I/System.out: 【已经消费产品数】:20	【现仓储量为】:0
2021-03-02 09:54:57.514 13063-13110/com.shan.myapplication I/System.out: consume1
2021-03-02 09:54:57.514 13063-13110/com.shan.myapplication I/System.out: consume2
2021-03-02 09:54:57.514 13063-13110/com.shan.myapplication I/System.out: 【要消费的产品数量】:50	【库存量】:0	暂时不能执行消费任务!
2021-03-02 09:54:57.515 13063-13110/com.shan.myapplication I/System.out: consume0
2021-03-02 09:54:57.515 13063-13119/com.shan.myapplication I/System.out: 【已经生产产品数】:80	【现仓储量为】:80
2021-03-02 09:54:57.516 13063-13110/com.shan.myapplication I/System.out: consume1
2021-03-02 09:54:57.516 13063-13110/com.shan.myapplication I/System.out: consume2
2021-03-02 09:54:57.517 13063-13110/com.shan.myapplication I/System.out: 开始消费产品
2021-03-02 09:54:57.517 13063-13110/com.shan.myapplication I/System.out: 【已经消费产品数】:50	【现仓储量为】:30
2021-03-02 09:54:57.518 13063-13118/com.shan.myapplication I/System.out: 【已经生产产品数】:10	【现仓储量为】:40

参考资料

java实现生产者和消费者

线程同步

Java实现生产者消费者的三种方式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值