《android开发-从小工到专家》学习记录(七)

对于Android平台来说,由于资源有限,最常使用的就是通过Executors.newFixedThreadPool(int size)函数来启动固定数量的线程,使用代码如下:

package zs;

import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ABC {
	private static void fixedThreadPool(int size)
		throws CancellationException,ExecutionException, InterruptedException
	{
		ExecutorService executorService = Executors.newFixedThreadPool(size);
		for(int i = 0;i < 10;i++)
		{
			Future<Integer> task = executorService.submit(new Callable<Integer>(){
				@Override
				public Integer call() throws Exception{
					System.out.println("执行线程: "+Thread.currentThread().getName());
					return add(50);
				}
			});
			System.out.println("第"+i+"次计算,结果:"+task.get());
		}
	}
	private static int add(int num)
	{
		int sum = 0;
		for(int i = 0;i<num;i++)
		{
			sum = sum + num;
		}
		return sum;
	}
	public static void main(String[] args)
	{
		try{
			fixedThreadPool(3);
		}catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
上述代码启动了一个含有3个线程的线程池,结果如下图:


结果中可以看出,线程池中一共有三个线程交替使用,完成了submit函数提交的十个任务。


有时候我们需要任务尽可能地快被执行,这就需要线程池中的线程足够多。也就是说此时需要使用空间来换时间,线程越多占用的内存消耗自然也就越大,但是,在正常情况下它的并发量也会更大,带来的是执行速度也越快,使用Executors的newCachedThreadPool函数可以实现---来了一个新任务,并且没有空闲线程可用,就马上创建一个线程来执行任务,使用代码如下:

package zs;

import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ABC {
	private static void fixedThreadPool(int size)
		throws CancellationException,ExecutionException, InterruptedException
	{
		ExecutorService executorService = Executors.newCachedThreadPool();
		for(int i = 0;i < 10;i++)
		{
			/*Future<Integer> task = executorService.submit(new Callable<Integer>(){
				@Override
				public Integer call() throws Exception{
					System.out.println("执行线程: "+Thread.currentThread().getName());
					return add(50);
				}
			});
			System.out.println("第"+i+"次计算,结果:"+task.get());*/
			executorService.submit(new Runnable(){
				@Override
				public void run()
				{
					System.out.println("执行线程: "+Thread.currentThread().getName()+",结果:"+add(50));
				}
			});
		}
	}
	private static int add(int num)
	{
		int sum = 0;
		for(int i = 0;i<num;i++)
		{
			sum = sum + num;
		}
		return sum;
	}
	public static void main(String[] args)
	{
		try{
			fixedThreadPool(3);
		}catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}	
注意到不在使用task.get()获得返回值,get方法会阻塞线程,从而使结果不明显,大家可以自己试试看,使用Runnable得到的结果如下:


可以看到该线程池为每个任务都创建了一个线程。


我们还可以使用ScheduledThreadPoolExecutor进行执行定时任务,执行代码可以翻阅网上其他资料或者翻阅此书,我没有敲,就不贴出来了。

在开发的过程中我们会使用到同步集合和同步锁来完成程序:

CopyOnWriteArrayList是一种同步集合的实现,适用于读多写少的条件,写入的方法使用Copy-On-Write优化策略,先把列表中的元素复制一份,然后进行修改,修改完成之后再将新的元素设置给这个列表,使用的是一种延时懒惰策略,这样做的好处是我们可以对列表进行并发地读;

ConcurrentHashMap使用锁分离技术,解决了HashTable容器在竞争激烈的并发环境下效率低下的问题,HashTable效率低下的原因是在高并发环境下,所有访问线程都必须竞争同一把锁,而ConcurrentHashMap中有多把锁,每一把锁用于锁容器其中一部分数据,这样多线程访问不同段的时候,线程间就不会存在竞争;

BlockingQueue是一种生产者消费者的实现,队列满时put函数会将调用线程阻塞,直到队列不满,take函数如果队列为空时,同样将线程阻塞,直到队列中有元素。

下面使用同步锁实现一个BlockingQueue:

package zs;

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

public class MyArrayBlockingQueue<T> {
	//数据数组
	private final T[] items;
	//锁
	private final Lock lock = new ReentrantLock();
	//队列满的条件
	private Condition notFull = lock.newCondition();
	//队列空的调节
	private Condition notEmpty = lock.newCondition();
	private int head;
	private int tail;
	//数据个数
	private int count;
	public MyArrayBlockingQueue(int maxSize)
	{
		items = (T[]) new Object[maxSize];
	}
	public MyArrayBlockingQueue()
	{
		this(10);
	}
	public void put(T t)
	{
		lock.lock();
		try{
			while(count == getCapacity())
			{
				System.out.println("数据已满,等待");
				notFull.await();
			}
			items[tail] = t;
			if(++tail == getCapacity())
			{
				tail = 0;
			}
			++count;
			notEmpty.signalAll();
		}catch(InterruptedException e)
		{
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	public T take()
	{
		lock.lock();
		try{
			while(count == 0)
			{
				System.out.println("暂无数据");
				notEmpty.await();
			}
			T ret = items[head];
			if(++head == getCapacity())
			{
				head = 0;
			}
			--count;
			notFull.signalAll();
			return ret;
		}catch(InterruptedException e)
		{
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
		return null;
	}
	public int getCapacity()
	{
		return items.length;
	}
	public int size()
	{
		lock.lock();
		try{return count;}
		finally{
			lock.unlock();
		}
	}
	public static void main(String[] args)
	{
		MyArrayBlockingQueue<Integer> aQueue 
		= new MyArrayBlockingQueue<Integer>();
		aQueue.put(3);
		aQueue.put(24);
		for(int i = 0;i<5;i++)
		{
			System.out.println(aQueue.take());
		}
	}
}
ReentrantLock类有一个重要的函数,newCondition(),该函数用于获取Lock上的一个条件,Condition与Lock绑定,用于实现线程间的通信,具体使用方法见上述代码,需要注意的是lock必须在finally块中释放,否则如果受保护的代码会弹出异常,锁就永远得不到释放,会出现问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值