链接地址:http://www.xx566.com/detail/98.html
上一篇:初级必备:Java版本区别与了解_JavaSE_多线程(1)说到,sun公司在Java 5中引入了一系列处理并发和多线程的功能类——Executor框架,其实更准确的说,是提供了java.util.concurrent工具包,在并发编程中使用的工具类,下面我们通过修改一下上一篇的示例来开始今天的学习:
package javase;
import java.util.concurrent.locks.ReentrantLock;
/**
* 多线程
*
* @Package javase
* @ClassName: LockTest
* @author Realfighter
* @date 2014-7-8 下午03:40:19
*/
public class LockTest {
private final static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
new LockThreadByThread().start();
new Thread(new LockThreadByRunnable()).start();
}
/**
* 任一线程持有锁时,都会在10次循环执行后才释放锁
* 去除lock,输出就比较随意了
* @Title: testLock
* @author Realfighter
* @date 2014-7-9 上午10:56:17
* @param name
* @param i
* void
*/
public static void testLock(String name, int i) {
lock.lock();
try {
for (int j = 0; j < 10; j++) {
System.out.println(name + " print >>>>>>" + i);
}
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
class LockThreadByThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
LockTest.testLock(Thread.currentThread().getName(), i);
}
}
}
class LockThreadByRunnable implements Runnable {
public void run() {
for (int i = 0; i < 50; i++) {
LockTest.testLock(Thread.currentThread().getName(), i);
}
}
}
ReentrantLock是一个可重入的互斥锁,它的功能比使用synchronized关键字的代码块,更强大,在资源竞争不很激烈的情况 下,synchronized的性能要优于ReentrantLock,但是在资源竞争激烈的情况,synchronized的性能会急剧下降,而 ReentrantLock则比较平稳。
ReentrantLock是Lock接口的一个实现,Lock实现提供了比使用synchronized关键字更广泛的锁操作,它允许更灵活的结构,可 以通过lock()方法获取锁,通过unlock()方法释放锁。那么,我们在获取锁之后又该如何对Thread进行操作呢,这里需要用到 Condition接口(关于Thread与Condition请参阅:初级必备:Java版本区别与了解_JavaSE_线程小结),Condition 将 Object监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用。Condition实例实质上被绑定到一个锁上,可以通过 lock.newCondition()来为特定lock获取Condition实例。
锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不 过,某些锁可能允许对共享资源并发访问,如ReadWriteLock的读取锁,readLock()方法返回用于读取操作的锁,writeLock() 方法返回用于写入操作的锁,写入锁是独占的,而读取锁可以由多个线程同时保持。与互斥锁相比,使用读-写锁所允许的并发性增强将带来更大的性能提高,也能 更好的保证同步。
java.util.concurrent提供的不只是这些,java.util.concurrent.atomic原子类的小工具包,支持在单个变量 上解除锁的线程安全编程。java.util.concurrent包下提供了多个接口和类,方便我们更好的进行并发编程,这里我们着重关注以下几个:接 口Executor,类Executors,接口Callable,接口Future,接口ExecutorService。Executor接口提供一 种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法;ExecutorService接口继承了Executor接 口,定义了一些生命周期的方法,用来操作和管理线程任务;Executors预置了创建线程池的工厂方法和返回Callable的方法;Callable 返回结果或可能抛出异常的任务;Future用于接收ExecutorService调用submit()后返回的结果,通过Future.get()方 法可以得到结果,线程执行完后需要手动调用ExecutorService.shutdown()方法来关闭线程工厂,来看下面的例子:
package javase;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 并发编程
*
* @Package javase
* @ClassName: ExecutorTest
* @author Realfighter
* @date 2014-7-9 下午12:35:40
*/
public class ExecutorTest {
public static void main(String[] args) {
ExecutorTest.testExecutor();
}
/**
* // 创建一个可根据需要创建新线程的线程池
* Executors.newCachedThreadPool();
* // 创建一个使用单个 worker线程的
* Executor Executors.newSingleThreadExecutor();
* // 创建一个可重用线程数为10的线程池
* int nThreads = 10;// 可重用线程数为10
* Executors.newFixedThreadPool(nThreads);
* //创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行
* int corePoolSize = 10;// 固定保存10个线程在池内
* Executors.newScheduledThreadPool(corePoolSize);
*
* @Title: testExecutor
* @author Realfighter
* @date 2014-7-9 下午01:14:00 void
*/
public static void testExecutor() {
ExecutorService pool = Executors.newSingleThreadExecutor();
Callable c = new Callable() {
// Callable会默认调用call()方法
public String call() throws Exception {
return "hello,relafighter";
}
};
//submit()方法提交一个 Runnable任务用于执行,并返回一个表示该任务的 Future
Future f = pool.submit(c);
try {
//get()方法获取线程执行后的结果
System.out.println(f.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//只有手动调用shutdown()才能关闭线程池
pool.shutdown();
}
}
总结:线程的并发编程以及java.util.concurrent包的应用是Java编程中的重点和难点,需要不断的积累和应用才能得心应手,关于多线程,当然还远远不止这些,一些队列等有关并发编程的应用,还是需要不间断的学习。