JAVA多线程实现的三种方式
<div class="article_manage clearfix">
<div class="article_l">
<span class="link_categories">
标签:
<a href="http://www.csdn.net/tag/java" target="_blank" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">java</a><a href="http://www.csdn.net/tag/多线程" target="_blank" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">多线程</a>
</span>
</div>
<div class="article_r">
<span class="link_postdate">2016-07-20 21:56</span>
<span class="link_view" title="阅读次数">3724人阅读</span>
<span class="link_comments" title="评论次数"> <a href="#comments" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_pinglun'])">评论</a>(0)</span>
<span class="link_collect tracking-ad" data-mod="popu_171"> <a href="javascript:void(0);" onclick="javascript:collectArticle('JAVA多线程实现的三种方式','51972820');return false;" title="收藏" target="_blank">收藏</a></span>
<span class="link_report"> <a href="#report" onclick="javascript:report(51972820,2);return false;" title="举报">举报</a></span>
</div>
</div> <style type="text/css">
.embody{
padding:10px 10px 10px;
margin:0 -20px;
border-bottom:solid 1px #ededed;
}
.embody_b{
margin:0 ;
padding:10px 0;
}
.embody .embody_t,.embody .embody_c{
display: inline-block;
margin-right:10px;
}
.embody_t{
font-size: 12px;
color:#999;
}
.embody_c{
font-size: 12px;
}
.embody_c img,.embody_c em{
display: inline-block;
vertical-align: middle;
}
.embody_c img{
width:30px;
height:30px;
}
.embody_c em{
margin: 0 20px 0 10px;
color:#333;
font-style: normal;
}
</style>
<script type="text/javascript">
$(function () {
try
{
var lib = eval("("+$("#lib").attr("value")+")");
var html = "";
if (lib.err == 0) {
$.each(lib.data, function (i) {
var obj = lib.data[i];
//html += '<img src="' + obj.logo + '"/>' + obj.name + " ";
html += ' <a href="' + obj.url + '" target="_blank">';
html += ' <img src="' + obj.logo + '">';
html += ' <em><b>' + obj.name + '</b></em>';
html += ' </a>';
});
if (html != "") {
setTimeout(function () {
$("#lib").html(html);
$("#embody").show();
}, 100);
}
}
} catch (err)
{ }
});
</script>
<div class="category clearfix">
<div class="category_l">
<img src="http://static.blog.csdn.net/images/category_icon.jpg">
<span>分类:</span>
</div>
<div class="category_r">
<label onclick="GetCategoryArticles('6119189','mccand1234','top','51972820');">
<span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_fenlei']);">java<em>(56)</em></span>
<img class="arrow-down" src="http://static.blog.csdn.net/images/arrow_triangle _down.jpg" style="display:inline;">
<img class="arrow-up" src="http://static.blog.csdn.net/images/arrow_triangle_up.jpg" style="display:none;">
<div class="subItem">
<div class="subItem_t"><a href="http://blog.csdn.net/mccand1234/article/category/6119189" target="_blank">作者同类文章</a><i class="J_close">X</i></div>
<ul class="subItem_l" id="top_6119189">
</ul>
</div>
</label>
</div>
</div>
目录(?)[+]
继承Thread类实现多线程实现Runnable接口方式实现多线程Thread本质上也是实现了Runnable接口的一个实例使用ExecutorServiceCallableFuture实现有返回结果的多线程实例可忽略
Java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。
继承Thread类实现多线程
继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:
public class MyThread extends Thread {
public void run() {
System.out.println(
"MyThread.run()");
}
}
12345
12345
在合适的地方启动线程如下:
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
myThread1.
start();
myThread2.
start();
1234
1234
实现Runnable接口方式实现多线程(Thread本质上也是实现了Runnable接口的一个实例)
如果自己的类已经extends另一个类,就无法直接extends Thread(java类的单继承,接口可以多继承),此时,必须实现一个Runnable接口,如下:
public class MyThread extends OtherClass implements Runnable {
public void run() {
System.out.println(
"MyThread.run()");
}
}
12345
12345
为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:
MyThread myThread
= new MyThread();
Thread thread = new Thread(myThread);
thread.start();
123
123
事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码(Thread的run方法的实现):
public void run() {
if (target !=
null) {
target.run();
}
}
12345
12345
使用ExecutorService、Callable、Future实现有返回结果的多线程
ExecutorService、Callable、Future这个对象实际上都是属于Executor框架中的功能类。想要详细了解Executor框架的可以访问http://www.javaeye.com/topic/366591。返回结果的线程是在JDK1.5中引入的新特征,确实很实用,有了这种特征我就不需要再为了得到返回值而大费周折。可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。下面提供了一个完整的有返回结果的多线程测试例子,在JDK1.5下验证过没问题可以直接使用。代码如下:
import java.util.concurrent.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
/**
* 有返回值的线程
*/
@SuppressWarnings(
"unchecked")
public class Test {
public static void main(String[] args)
throws ExecutionException,
InterruptedException {
System.out.println(
"----程序开始运行----");
Date date1 =
new Date();
int taskSize =
5;
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
List<Future> list =
new ArrayList<Future>();
for (
int i =
0; i < taskSize; i++) {
Callable c =
new MyCallable(i +
" ");
Future f = pool.submit(c);
list.add(f);
}
pool.shutdown();
for (Future f : list) {
System.out.println(
">>>" + f.get().toString());
}
Date date2 =
new Date();
System.out.println(
"----程序结束运行----,程序运行时间【"
+ (date2.getTime() - date1.getTime()) +
"毫秒】");
}
}
class MyCallable implements Callable<Object> {
private String taskNum;
MyCallable(String taskNum) {
this.taskNum = taskNum;
}
public Object
call()
throws Exception {
System.out.println(
">>>" + taskNum +
"任务启动");
Date dateTmp1 =
new Date();
Thread.sleep(
1000);
Date dateTmp2 =
new Date();
long time = dateTmp2.getTime() - dateTmp1.getTime();
System.out.println(
">>>" + taskNum +
"任务终止");
return taskNum +
"任务返回运行结果,当前任务时间【" + time +
"毫秒】";
}
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
运行结果
代码说明: 上述代码中Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
public static ExecutorService
newFixedThreadPool(
int nThreads)
1
1
创建固定数目线程的线程池。
public static ExecutorService
newCachedThreadPool()
1
1
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService
newSingleThreadExecutor()
1
1
创建一个单线程化的Executor。
public static ScheduledExecutorService
newScheduledThreadPool(
int corePoolSize)
1
1
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
实例(可忽略):
public List<Integer> setShopType(
List<Integer> shopIDs, int bizID, int shopType, int operatorID) {
for(
Integer shopId:shopIDs){
Response res
= rotateService
.initRotateGroupWithoutBizValidate(shopId,bizID);
if(
!res
.isSuccess()){
throw
new ApplicationException(res
.getComment());
}
}
List<RotateGroupDTO
> rotateGroupDTOs
= rotateGroupService
.getRotateGroup(bizID, shopIDs);
List<Integer> rotateGroupIDs
= Lists
.transform(rotateGroupDTOs,
new Function
<RotateGroupDTO,
Integer>() {
@Override
public Integer apply(RotateGroupDTO input) {
return input
.getId();
}
});
Map<Integer,
List<RotateGroupShopDTO
>> rotateGroupShopMap
= rotateGroupShopService
.getRotateGroupShop(rotateGroupIDs);
List<RotateGroupShopDTO
> rotateGroupShopDTOList
= Lists
.newArrayList();
for (
Integer rotateGroupId : rotateGroupShopMap
.keySet()) {
rotateGroupShopDTOList
.addAll(rotateGroupShopMap
.get(rotateGroupId));
}
List<Integer> shopIdList
= Lists
.transform(rotateGroupShopDTOList,
new Function
<RotateGroupShopDTO,
Integer>() {
@Override
public Integer apply(RotateGroupShopDTO input) {
return input
.getShopID();
}
});
ShopHistoryModel model
= ShopHistoryModel
.builder()
.shopIdList(shopIdList)
.bizId(bizID)
.shopHistoryType(SubActionTypeEnum
.VIP_MARK
.getCode())
.build();
Map<Integer,
Integer> oldValue
= (
Map<Integer,
Integer>) bigCustomerProcessor
.getData(model);
Response
<Boolean
> response
= rotateService
.setRotateGroupBigCustomer(rotateGroupIDs, bizID, shopType);
Map<Integer,
Integer> newValue
= (
Map<Integer,
Integer>) bigCustomerProcessor
.getData(model);
if (response
.isSuccess()) {
bigCustomerProcessor
.compareAndCreateLog(model, oldValue, newValue,operatorID);
return null;
}
return shopIDs;
}
@Override
public List<Integer> batchSetShopType(
List<Integer> shopIDs, final int bizID, final int shopType, final int operatorID) throws Exception {
String threadSize
= LionConfigUtils
.getProperty(
"roc-operation-tools-pc-web.threadSize",
"50");
ExecutorService executorService
= Executors
.newFixedThreadPool(
Integer.parseInt(threadSize));
List<Integer> wrongList
= Lists
.newArrayList();
List<Callable
<List<Integer>>> tasks
= Lists
.newArrayList();
String batchSize
= LionConfigUtils
.getProperty(
"roc-operation-tools-pc-web.batchSize",
"200");
List<List<Integer>> batchShopsList
= Lists
.partition(shopIDs,
Integer.parseInt(batchSize));
for (final
List<Integer> shopids : batchShopsList) {
tasks
.add(
new Callable
<List<Integer>>() {
@Override
public List<Integer> call() throws Exception {
return setShopType(shopids, bizID, shopType, operatorID);
}
});
}
Stopwatch stopwatch
= Stopwatch
.createStarted();
List<Future
<List<Integer>>> futures
= executorService
.invokeAll(tasks);
for (Future
<List<Integer>> future : futures) {
while (
true) {
if (future
.isDone()
&& !future
.isCancelled()) {
if(CollectionUtils
.isNotEmpty(future
.get())){
wrongList
.addAll(future
.get());
}
break;
}
}
}
log.info(
"batchSetShopType cost time:" + stopwatch
.elapsed(TimeUnit
.MILLISECONDS)
+ "ms");
executorService
.shutdown();
return wrongList;
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
参考: http://blog.csdn.net/aboy123/article/details/38307539 http://www.iteye.com/topic/366591 http://mars914.iteye.com/blog/1508429 http://www.cnblogs.com/gw811/archive/2012/10/15/2724602.html
(function () {('pre.prettyprint code').each(function () { var lines =
(this).text().split(′\n′).length;var
numbering = $('
').addClass('pre-numbering').hide();
(this).addClass(′has−numbering′).parent().append(
numbering); for (i = 1; i