迅雷2014校招笔试题之多线程编程

题意:

大体如下:android中Activity开启两个线程,一个Produce线程,一个Customer线程,共享Integer[10]数组,Produce线程不断向数组中写入1000,写满后等待,Customer线程不断清空数组内容,当数组全被清空后,通知Produce线程写入数据,Activity要及时刷新当前Integer数组内容size。

分析

从题意可知,在Java方面,这里涉及到两个线程共享一个数组,也就是说当一个线程在运行操作数组时,另一个线程只能等待,否则将出现竞争状态,即一个线程在运行时,另一个线程只能处于阻塞状态。在Andriod方面,因为在Acitivty中要及时刷新当前Integer数组的内容size,所以在UI主线程中要实时读取Integer的size,这个读取是在主线程完成的,而两个子线程可以把改变的信息通过handler发送到主线程,进而主线程进行解析信息,根据信息显示。

实现:

分两种方法实现,一种为比较旧的版本,用到了java旧版本的监听器,另一种使用较新版本的类,这些类内部具有阻塞功能,三个具体的阻塞队列为:ArrayBlockingQueue,  LinkBlockingQueue和PriorityBlockingQueue。它们都在java.util.concurrent的包中。其中,ArrayBlockingQueue使用数组实现阻塞队列。LinkBlockingQueue使用链表实现阻塞队列。

1 利用监听器(monitor)对象:

在activity的xml布局中定义了两个TextView,分别用来显示实时数组大小和写入清楚情况

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >
    
    <TextView 
        android:id = "@+id/size"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:textSize="20.0sp"
		android:padding="5dp"
	/>
    
	 <ScrollView   
        android:id="@+id/scrollView01"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent"> 
	    <TextView 
	        android:id="@+id/produce_comsumer"
	        android:gravity="center_vertical"
	        android:layout_width="fill_parent"
	        android:layout_height="wrap_content"
	        />
	 </ScrollView> 
</LinearLayout>
 

定义了一个类Buffer,完成包括write(写入方法)和read(清除方法)。程序中生成了两个状态,分别为notFull和notEmpty,作用具体看程序注解。而uiHandler主要用于主线程和子线程的消息通信。当子线程发生变化之后,通过sendMessage方法发生消息,然后主线程通过CallBack得到Message

package gibbon.thread.threadtestinandroid;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import android.R.integer;
import android.os.Message;

public class Buffer {
	private static Lock lock = new ReentrantLock();
	private static Condition notEmpty = lock.newCondition();
	private static Condition notFull = lock.newCondition();
	private static final int CAPACITY = 10;
	
	protected LinkedList<Integer> queue = new LinkedList<Integer>();
	
	protected void write(int value){
		lock.lock();
		try {
			if(queue.size() == CAPACITY){
				System.out.println("Wait for not noFull condition");
				Message msg = new Message();
				msg.what = Definition.FULL;
				ConsumerProducerActivity.uiHandler.sendMessage(msg);
				notFull.await(); //因为已经满了,所以notFull必须等待,等取走数据才能继续运行(即只能等待下面的数据取走,然后调用signal唤醒)
			}
			
			queue.offer(value);
			Message msg = new Message();
			msg.what = Definition.NOTEMPTY;
			ConsumerProducerActivity.uiHandler.sendMessage(msg);
			notEmpty.signal(); //因为非空,所以唤醒非空功能
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	protected int read(){
		lock.lock();
		int value = 0;
		try {
			if(queue.size() == 0){
				System.out.println("\t\tWait for notEmpty condition");
				Message msg = new Message();
				msg.what = Definition.Empty;
				ConsumerProducerActivity.uiHandler.sendMessage(msg); //这里的Message对象在线程中只能多次创建,若不这样,
										//则如在主线程用到了该对象的同时,下面的线程又进行了修改,则就发生变化
				notEmpty.await(); //这里就可以等待上面的数据写入之后,通过notEmpty来唤醒
			}
			
			value = queue.remove();
			Message msg = new Message();
			msg.what = Definition.NOTEMPTY;
			ConsumerProducerActivity.uiHandler.sendMessage(msg);
			notFull.signal(); //取走数据了,换新上面的notFull等待
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
		return value;
	}
}

然后在acitivty中启动Producer和Customer两个线程,为了方便,只循环了50次。

package gibbon.thread.threadtestinandroid;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.R.integer;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class ConsumerProducerActivity extends Activity {
	protected static Handler uiHandler;
	//protected static Handler comsumerHandler;
	private TextView sizeTextView;
	private TextView producer_consumer;
	private ExecutorService executorService;
	private static String str;
	private static Buffer buffer = new Buffer();
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_consumer_producer);

		uiHandler = new Handler(new UiHandler());
		init();	
	}

	private void init(){
		sizeTextView = (TextView)findViewById(R.id.size);
		producer_consumer = (TextView)findViewById(R.id.produce_comsumer);
		
		executorService = Executors.newFixedThreadPool(2);
		executorService.execute(new ProducerTask());
		executorService.execute(new ComsumerTask());
		executorService.shutdown();
	}
	
	public static class ProducerTask implements Runnable{
		@Override
		public void run(){
			int count = 50;
			while(count-- > 0){
				buffer.write(1000);
				try {
					Thread.sleep((int)(Math.random()*10000));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	public static class ComsumerTask implements Runnable{
		@Override
		public void run(){
			int count = 50;
			int value = 0;
			while(count-- > 0){
				buffer.read();
				try {
					Thread.sleep((int)(Math.random()*10000));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.consumer_producer, menu);
		return true;
	}
	
	public class UiHandler implements Callback{

		@Override
		public boolean handleMessage(Message msg) {
			// TODO Auto-generated method stub
			sizeTextView.setText("大小为:" + buffer.queue.size());
			synchronized (msg) {
				switch (msg.what) {
				case Definition.Empty:
					str += Definition.EMPTY_STRING;
					str += "\n";
					break;
				case Definition.FULL:
					str += Definition.FULL_STRING;
					str += "\n";
					break;
				case Definition.NOTEMPTY:
					str += Definition.NOTEMPTY_STRING;
					str += "\n";
					break;
				case Definition.NOTFULL:
					str += Definition.NOTFULL_STRING;
					str += "\n";
					break;
				default:
					break;
				}
			}
			producer_consumer.setText(str);
			return false;
		}
		
	}

}

另外附带一些自定义变量:

package gibbon.thread.threadtestinandroid;

import android.R.integer;

public class Definition {
	protected static final int NOTFULL = 1;
	protected static final int NOTEMPTY = 2;
	protected static final int BUFFERSZIE = 3;
	protected static final int FULL = 4;
	protected static final int Empty = 5;
	protected static final String NOTFULL_STRING = "Wait for not noFull condition";
	protected static final String NOTEMPTY_STRING = "\tWait for notEmpty condition";
	protected static final String FULL_STRING = "\t\tBufferSize FuLL";
	protected static final String EMPTY_STRING = "\t\t\tBufferSize Empty";
}

运行结果如下:


2 使用ArrayBlockingQueue:

程序如下:

public class ConsumerProducerActivity extends Activity {
	protected static Handler uiHandler;
	private TextView sizeTextView;
	private TextView producer_consumer;
	private ExecutorService executorService;
	private static String str;
	private static Buffer buffer = new Buffer();
	private static ArrayBlockingQueue<Integer> integer_buffer = new ArrayBlockingQueue<Integer>(10);
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_consumer_producer);

		uiHandler = new Handler(new UiHandler());
		init();	
	}

	private void init(){
		sizeTextView = (TextView)findViewById(R.id.size);
		producer_consumer = (TextView)findViewById(R.id.produce_comsumer);
		
		executorService = Executors.newFixedThreadPool(2);
		//executorService.execute(new ProducerTask());
		//executorService.execute(new ComsumerTask());
		executorService.execute(new Producer());
		executorService.execute(new Consumer());
		executorService.shutdown();
	}
public static class Producer implements Runnable{
		@Override
		public void run(){
			try {
				int i = 50;
				while(i-- >0){
					if(integer_buffer.size() == 10){
						Message msg = new Message();
						msg.what = Definition.FULL;
						uiHandler.sendMessage(msg);
					}
					integer_buffer.put(1000);
					Message msg = new Message();
					msg.what = Definition.NOTEMPTY;
					uiHandler.sendMessage(msg);
					Thread.sleep((int)(Math.random()*10000));
				}
			} catch (InterruptedException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
	}
	
	public static class Consumer implements Runnable{
		@Override
		public void run(){
			try {
				int i = 50;
				while(i-- >0){
					if(integer_buffer.size() == 0){
						Message msg = new Message();
						msg.what = Definition.Empty;
						uiHandler.sendMessage(msg);
					}
					integer_buffer.take();
					Message msg = new Message();
					msg.what = Definition.NOTFULL;
					uiHandler.sendMessage(msg);
					Thread.sleep((int)(Math.random()*10000));
				}
			} catch (InterruptedException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.consumer_producer, menu);
		return true;
	}
	
	public class UiHandler implements Callback{

		@Override
		public boolean handleMessage(Message msg) {
			// TODO Auto-generated method stub
			sizeTextView.setText("大小为:" + integer_buffer.size());
			switch (msg.what) {
			case Definition.Empty:
				str += Definition.EMPTY_STRING;
				str += "\n";
				break;
			case Definition.FULL:
				str += Definition.FULL_STRING;
				str += "\n";
				break;
			case Definition.NOTEMPTY:
				str += Definition.NOTEMPTY_STRING;
				str += "\n";
				break;
			case Definition.NOTFULL:
				str += Definition.NOTFULL_STRING;
				str += "\n";
				break;
			default:
				break;
			}

			producer_consumer.setText(str);
			return false;
		}
		
	}
}

这个比较容易理解,因为ArrayBlockingQueue具有能自行实现阻塞队列


PS:转发请注明出处!

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值