Java多线程学习(生产者、消费者)

        今天在草稿里翻到一篇古董级学习心得,分享出来给大家。


学习多线程同步的生产者和消费者问题,目标是两个线程共同访问一个仓库,一个生产,一个消费,仓库大小为10,总共要生产50个产品,代码如下:

com.example.producercomsumer;
 
import java.util.LinkedList;
import java.util.Random;
 
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
 
public class MainActivity extends Activity {
 
    public static final String TAG = "";
    public static final int FULL_SIZE = 10;
    private LinkedList mStorage = new LinkedList();
    private static final int TOTAL_NUM = 50;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        new Producer().start();
        new Comsumer().start();
    }
 
    class Producer extends Thread {
        int total = 0;
 
        public void run() {
 
            Log.d(TAG, "Start Produce>>>>>>>>>>>>>>>");
            while (total < TOTAL_NUM) {
 
                synchronized (mStorage) {
                    while (mStorage.size() == FULL_SIZE) {
                        try {
                            mStorage.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
 
                    String product = "PRODUCT("  + new Random().nextInt() + ")";
                    total++;
 
                    mStorage.add(product);
 
                    Log.d(TAG, "Produce:" + product + " storage size:" + mStorage.size() + " , total:" + total);
 
                    mStorage.notify();
 
                    Thread.yield();
                }
 
            }
//            Log.d(TAG, "End Produce<<<<<<<<<<<<<<<");
        }
    }
 
    class Comsumer extends Thread {
        public void run() {
 
            while (true) {
                synchronized (mStorage) {
                    while (mStorage.size() == 0) {
                        try {
                            mStorage.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
 
                    String product = mStorage.removeFirst();
                    Log.d(TAG, "Consume : " + product + " storage size:" + mStorage.size());
 
                    mStorage.notify();
 
                    Thread.yield();
 
                }
            }
        }
    }
}

运行结果:

D/ ( 8368): Start Produce>>>>>>>>>>>>>>>
D/ ( 8368): Produce:PRODUCT(638723307) storage size:1 , total:1
D/ ( 8368): Produce:PRODUCT(1004619511) storage size:2 , total:2
D/ ( 8368): Produce:PRODUCT(-498194369) storage size:3 , total:3
D/ ( 8368): Produce:PRODUCT(723383389) storage size:4 , total:4
D/ ( 8368): Produce:PRODUCT(567560084) storage size:5 , total:5
D/ ( 8368): Produce:PRODUCT(1379010839) storage size:6 , total:6
D/ ( 8368): Produce:PRODUCT(1154317481) storage size:7 , total:7
D/ ( 8368): Produce:PRODUCT(941936088) storage size:8 , total:8
D/ ( 8368): Produce:PRODUCT(2022311000) storage size:9 , total:9
D/ ( 8368): Produce:PRODUCT(1809929607) storage size:10 , total:10
I/ZDClock ( 5221): ScheduleReceiver finish…
D/ ( 8368): Consume : PRODUCT(638723307) storage size:9
D/ ( 8368): Produce:PRODUCT(-1766711493) storage size:10 , total:11
D/ ( 8368): Consume : PRODUCT(1004619511) storage size:9
D/ ( 8368): Produce:PRODUCT(-549750722) storage size:10 , total:12
D/ ( 8368): Consume : PRODUCT(-498194369) storage size:9
D/ ( 8368): Produce:PRODUCT(-1021068124) storage size:10 , total:13
D/ ( 8368): Consume : PRODUCT(723383389) storage size:9
D/ ( 8368): Produce:PRODUCT(-1835566222) storage size:10 , total:14
D/ ( 8368): Consume : PRODUCT(567560084) storage size:9
D/ ( 8368): Produce:PRODUCT(2075806421) storage size:10 , total:15
D/ ( 8368): Consume : PRODUCT(1379010839) storage size:9
D/ ( 8368): Produce:PRODUCT(-1123780757) storage size:10 , total:16
D/ ( 8368): Consume : PRODUCT(1154317481) storage size:9
D/ ( 8368): Produce:PRODUCT(-1505451665) storage size:10 , total:17
D/ ( 8368): Consume : PRODUCT(941936088) storage size:9
D/ ( 8368): Produce:PRODUCT(-310421582) storage size:10 , total:18
D/ ( 8368): Consume : PRODUCT(2022311000) storage size:9
D/ ( 8368): Produce:PRODUCT(-952567496) storage size:10 , total:19
D/ ( 8368): Consume : PRODUCT(1809929607) storage size:9
D/ ( 8368): Produce:PRODUCT(207450438) storage size:10 , total:20
D/ ( 8368): Consume : PRODUCT(-1766711493) storage size:9
D/ ( 8368): Produce:PRODUCT(-174220471) storage size:10 , total:21
D/ ( 8368): Consume : PRODUCT(-549750722) storage size:9
D/ ( 8368): Produce:PRODUCT(-987564322) storage size:10 , total:22
D/ ( 8368): Consume : PRODUCT(-1021068124) storage size:9
D/ ( 8368): Produce:PRODUCT(-1369619979) storage size:10 , total:23
D/ ( 8368): Consume : PRODUCT(-1835566222) storage size:9
D/ ( 8368): Produce:PRODUCT(120127762) storage size:10 , total:24
D/ ( 8368): Consume : PRODUCT(2075806421) storage size:9
D/ ( 8368): Produce:PRODUCT(-263466892) storage size:10 , total:25
D/ ( 8368): Consume : PRODUCT(-1123780757) storage size:9
D/ ( 8368): Produce:PRODUCT(853459165) storage size:10 , total:26
D/ ( 8368): Consume : PRODUCT(-1505451665) storage size:9
D/ ( 8368): Produce:PRODUCT(471788256) storage size:10 , total:27
D/ ( 8368): Consume : PRODUCT(-310421582) storage size:9
D/ ( 8368): Produce:PRODUCT(1667203089) storage size:10 , total:28
D/ ( 8368): Consume : PRODUCT(-952567496) storage size:9
D/ ( 8368): Produce:PRODUCT(1285532180) storage size:10 , total:29
D/ ( 8368): Consume : PRODUCT(207450438) storage size:9
D/ ( 8368): Produce:PRODUCT(-737646103) storage size:10 , total:30
D/ ( 8368): Consume : PRODUCT(-174220471) storage size:9
D/ ( 8368): Produce:PRODUCT(-1108928791) storage size:10 , total:31
D/ ( 8368): Consume : PRODUCT(-987564322) storage size:9
D/ ( 8368): Produce:PRODUCT(8382015) storage size:10 , total:32
D/ ( 8368): Consume : PRODUCT(-1369619979) storage size:9
D/ ( 8368): Produce:PRODUCT(-373673643) storage size:10 , total:33
D/ ( 8368): Consume : PRODUCT(120127762) storage size:9
D/ ( 8368): Produce:PRODUCT(885224758) storage size:10 , total:34
D/ ( 8368): Consume : PRODUCT(-263466892) storage size:9
D/ ( 8368): Produce:PRODUCT(480084166) storage size:10 , total:35
D/ ( 8368): Consume : PRODUCT(853459165) storage size:9
D/ ( 8368): Produce:PRODUCT(1689349959) storage size:10 , total:36
D/ ( 8368): Consume : PRODUCT(471788256) storage size:9
D/ ( 8368): Produce:PRODUCT(277721569) storage size:10 , total:37
D/ ( 8368): Consume : PRODUCT(1667203089) storage size:9
D/ ( 8368): Produce:PRODUCT(-105873084) storage size:10 , total:38
D/ ( 8368): Consume : PRODUCT(1285532180) storage size:9
D/ ( 8368): Produce:PRODUCT(1088002753) storage size:10 , total:39
D/ ( 8368): Consume : PRODUCT(-737646103) storage size:9
D/ ( 8368): Produce:PRODUCT(607836125) storage size:10 , total:40
D/ ( 8368): Consume : PRODUCT(-1108928791) storage size:9
D/ ( 8368): Produce:PRODUCT(1803250958) storage size:10 , total:41
D/ ( 8368): Consume : PRODUCT(8382015) storage size:9
D/ ( 8368): Produce:PRODUCT(1369254199) storage size:10 , total:42
D/ ( 8368): Consume : PRODUCT(-373673643) storage size:9
D/ ( 8368): Produce:PRODUCT(-1414804167) storage size:10 , total:43
D/ ( 8368): Consume : PRODUCT(885224758) storage size:9
D/ ( 8368): Produce:PRODUCT(-1863036635) storage size:10 , total:44
D/ ( 8368): Consume : PRODUCT(480084166) storage size:9
D/ ( 8368): Produce:PRODUCT(1626666537) storage size:10 , total:45
D/ ( 8368): Consume : PRODUCT(1689349959) storage size:9
D/ ( 8368): Produce:PRODUCT(1244610879) storage size:10 , total:46
D/ ( 8368): Consume : PRODUCT(277721569) storage size:9
D/ ( 8368): Produce:PRODUCT(-1931891364) storage size:10 , total:47
D/ ( 8368): Consume : PRODUCT(-105873084) storage size:9
D/ ( 8368): Produce:PRODUCT(1981405023) storage size:10 , total:48
D/ ( 8368): Consume : PRODUCT(1088002753) storage size:9
D/ ( 8368): Produce:PRODUCT(-1218182155) storage size:10 , total:49
D/ ( 8368): Consume : PRODUCT(607836125) storage size:9
D/ ( 8368): Produce:PRODUCT(-1601776808) storage size:10 , total:50
D/ ( 8368): Consume : PRODUCT(1803250958) storage size:9
D/ ( 8368): Consume : PRODUCT(1369254199) storage size:8
D/ ( 8368): Consume : PRODUCT(-1414804167) storage size:7
D/ ( 8368): Consume : PRODUCT(-1863036635) storage size:6
D/ ( 8368): Consume : PRODUCT(1626666537) storage size:5
D/ ( 8368): Consume : PRODUCT(1244610879) storage size:4
D/ ( 8368): Consume : PRODUCT(-1931891364) storage size:3
D/ ( 8368): Consume : PRODUCT(1981405023) storage size:2
D/ ( 8368): Consume : PRODUCT(-1218182155) storage size:1
D/ ( 8368): Consume : PRODUCT(-1601776808) storage size:0

发现是这样wait的:

while (mStorage.size() == FULL_SIZE) {
    try {
        mSync.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
好奇为什么用while而不用if,actually, 当我把它改为if后,程序仍然可以正常运行。
像这样:
class Producer extends Thread {
        int total = 0;
 
        public void run() {
 
            Log.d(TAG, "Start Produce》》》》》》》》》》》》》》》》》》》》");
            while (total < TOTAL_NUM) {
 
                synchronized (mSync) {
                    if (mStorage.size() == FULL_SIZE) {
                        try {
                            mSync.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
 
                    String product = "PRODUCT("  + new Random().nextInt() + ")";
                    total++;
 
                    mStorage.add(product);
 
                    Log.d(TAG, "Produce:" + product + " storage size:" + mStorage.size() + " , total:" + total);
 
                    mSync.notify();
 
                    Thread.yield();
                }
 
            }
            Log.d(TAG, "End Produce《《《《《《《《《《《《《《《");
        }
    }
 
    class Comsumer extends Thread {
        public void run() {
 
            while (true) {
                synchronized (mSync) {
                    if (mStorage.size() == 0) {
                        try {
                            mSync.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
 
                    String product = mStorage.removeFirst();
                    Log.d(TAG, "Consume : " + product + " storage size:" + mStorage.size());
 
                    mSync.notify();
 
                    Thread.yield();
 
                }
            }
        }
    }

现在尝试把事情变得好玩点,添加一个消费者,变成一个人生产,两个人消费:

class Comsumer extends Thread {
 
        private String mName;
 
        public Comsumer (String name){
            mName = name;
        }
 
        public void run() {
 
            while (true) {
                synchronized (mSync) {
                    if (mStorage.size() == 0) {
                        try {
                            mSync.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
 
                    String product = mStorage.removeFirst();
                    Log.d(TAG, "Consumer " + mName + " consume " + product + " storage size:" + mStorage.size());
 
                    mSync.notify();
 
                    Thread.yield();
 
                }
            }
        }
    }

这样调用:

new Producer().start();
new Comsumer("herbert").start();
new Comsumer("wellings").start();

OK, 运行,

        第一次没问题,都被herbert消费了,

        第二次也没问题,wellings也消费了10个,

        第三次,程序挂了

  W/dalvikvm( 3552): threadid=14: thread exiting with uncaught exception (group=0x40a4f300) E/AndroidRuntime( 3552): FATAL EXCEPTION: Thread-694 E/AndroidRuntime( 3552): java.util.NoSuchElementException E/AndroidRuntime( 3552): at java.util.LinkedList.removeFirstImpl(LinkedList.java:689) E/AndroidRuntime( 3552): at java.util.LinkedList.removeFirst(LinkedList.java:676) E/AndroidRuntime( 3552): at com.example.producercomsumer.MainActivity$Comsumer.run(MainActivity.java:85) W/ActivityManager( 1848): Force finishing activity com.example.producercomsumer/.MainActivity

什么情况? 

加了打印消息后看得更清楚:

String product = null; 
   try {    
         product = mStorage.removeFirst();
   } catch (Exception e) {
         e.printStackTrace();
   }
   Log.d(TAG, "Consumer " + mName + " consume " + product + " storage size:" + mStorage.size());

原来是wellings试图去空仓库里拿东西,不是有if (仓库为空) wait(); 吗? 

答案是有两个消费线程被notify,只有先被nogify的那个线程可以拿到最后一个,后面的线程也被notify到了(说明一个问题:notify()会叫醒所有wait()的线程,相当于notifyAll()?) 但是拿不东西就会出错。

现在才发现while() 和 if()的区别

        while()被notify到后,会循环到前面再检测一次仓库是否为空,而if()不会再次检测,这就是为什么我看到的代码都是用while的原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值