java执行程序默认多线程吗_Java多线程 执行程序(1)
本文由作者收集整理所得,作者不保證內(nèi)容的正確行,轉(zhuǎn)載請(qǐng)標(biāo)明出處。
作者:關(guān)新全
Java多線程
執(zhí)行程序(1)
1.1
Thread類
static Thread.currentThread
返回當(dāng)前正在執(zhí)行的線程對(duì)象的引用。
join 等待線程終止。
yield 暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程。
Demo1-1中給出的程序中,主函數(shù)中創(chuàng)建了兩個(gè)線程,每個(gè)子線程第一條輸出語句執(zhí)行結(jié)束后,放棄了執(zhí)行權(quán),從而讓其他線程有機(jī)會(huì)繼續(xù)執(zhí)行。這樣就會(huì)看到子線程1和子線程2交叉輸出的信息。在主線程中使用了join方法,阻塞等待子線程執(zhí)行結(jié)束,當(dāng)兩個(gè)子線程將其內(nèi)部的信息全部輸出后,主線程才將其線程線性輸出。(Thread.currentThread的輸出格式為,[子線程名,線程優(yōu)先級(jí),線程組名])。最后,在main函數(shù)內(nèi)部需要調(diào)用內(nèi)部類,內(nèi)部類應(yīng)當(dāng)為static。一般情況下,內(nèi)部類和內(nèi)部接口都應(yīng)當(dāng)是static的。
Demo 1-1 Thread
類的用法
package com.upc.upcgrid.guan.advancedJava.chapter02;
public class YieldTest {
public static class ThreadImpl implements Runnable{
@Override
public void run() {
System.err.println(Thread.currentThread());
Thread.yield();
System.err.println(Thread.currentThread());
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ThreadImpl());
Thread t2 = new Thread(new ThreadImpl());
t1.start();
t2.start();
t1.join();
t2.join();
System.err.println(Thread.currentThread());
}
}
Demo1-1 輸出結(jié)果
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[main,5,main]
1.2 Executor
接口
Executor可以定制創(chuàng)建特殊的子線程。例如,在創(chuàng)建一系列的子線程時(shí),對(duì)子線程進(jìn)行同樣的配置,如果,需要修改或增強(qiáng)子線程的開啟或配置,只需修改Executor的實(shí)現(xiàn)即可。
在Demo1-2中,主線程通過Executor接口創(chuàng)建和執(zhí)行一個(gè)新的線程。在Executor接口的ExecutorInterface實(shí)現(xiàn)中,可以對(duì)所有的線程進(jìn)行一些默認(rèn)的配置,然后啟動(dòng)執(zhí)行這個(gè)線程。如果,此時(shí)我們需要修改這個(gè)系列線程的優(yōu)先級(jí),只需要修改ExecutorInterface接口中的相應(yīng)值即可,無需修改代碼中的所有創(chuàng)建線程的地方。(有時(shí)可以在Executor的executor的方法實(shí)現(xiàn)中使用一定的線程調(diào)度策略,這樣可以為線程調(diào)度提供靈活性,當(dāng)修改線程調(diào)度的實(shí)現(xiàn)時(shí),不影響外部使用的代碼)。
Demo1-3實(shí)現(xiàn)了一個(gè)線程優(yōu)先隊(duì)列的Executor,在這樣的Executor中,每次提交的任務(wù)會(huì)被放入一個(gè)隊(duì)列中,Executor最多只開啟一個(gè)線程執(zhí)行這個(gè)隊(duì)列中的任務(wù),而且隊(duì)列使用優(yōu)先級(jí)策略,就是優(yōu)先級(jí)高的線程將會(huì)先被Executor執(zhí)行,優(yōu)先級(jí)低的線程將需等待優(yōu)先級(jí)高的線程執(zhí)行結(jié)束后,才能獲得執(zhí)行權(quán)。從代碼中看出,創(chuàng)建了5個(gè)線程,設(shè)置了不同的優(yōu)先級(jí),并提交個(gè)Executor去執(zhí)行。從執(zhí)行結(jié)果可以看出,線程基本是按照線程優(yōu)先級(jí)次序執(zhí)行的(線程優(yōu)先級(jí)5先執(zhí)行,因?yàn)樵谒峤坏臅r(shí)候隊(duì)列中并沒有其他線程,他的優(yōu)先級(jí)最高,因此它被最先執(zhí)行了,也就是說這個(gè)優(yōu)先級(jí)還與線程的提交次序有關(guān))。Executor更傾向于開啟一個(gè)線程,在稍后對(duì)ExecutorFactory介紹時(shí),可以看出,他們一個(gè)是執(zhí)行線程,一個(gè)是創(chuàng)建線程。
Demo 1-2
Executor接口的使用
package com.upc.upcgrid.guan.SpecialUse.chapter01;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.Executor;
public class ExecutorInterface implements Executor{
@Override
public void execute(Runnable command) {
Thread t = new Thread(command);
t.setDaemon(false);
t.setPriority(6);
t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e)
{
System.err.println(e.getMessage());
}
});
t.start();
}
private static class RunnableImpl implements Runnable{
@Override
public void run() {
System.err.println(Thread.currentThread());
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorInterface e = new ExecutorInterface();
e.execute(new RunnableImpl());
e.execute(new RunnableImpl());
}
}
Demo1-3 線程池的初探
package com.upc.upcgrid.guan.SpecialUse.chapter01;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.PriorityBlockingQueue;
public class ExecutorInterfaceWithSchedule
implements Executor{
private BlockingQueue
queue = new PriorityBlockingQueue();
private Thread t;
public ExecutorInterfaceWithSchedule() {
Thread inner =new Thread(new Runnable() {
@Override
public void run() {
try {
while(true)
{
t = new Thread(queue.take());
t.start();
t.join();//等待線程結(jié)束
}
} catch (InterruptedException e) {
}
}
});
inner.setDaemon(true);
inner.start();
}
@Override
public void execute(Runnable command) {
try {
queue.put(command);
} catch (InterruptedException e) {
}
}
private static class ThreadImpl implements Runnable,Comparable{
public int priority;
public ThreadImpl(int priority) {
this.priority = priority;
}
@Override
public void run() {
System.err.println(Thread.currentThread() +
String.valueOf(priority));
}
@Override
public int compareTo(ThreadImpl o) {
return o.priority > priority?1:0;
}
}
public static void main(String[] args) throws InterruptedException {
ThreadImpl t1 = new ThreadImpl(5);
ThreadImpl t2 = new ThreadImpl(6);
ThreadImpl t3 = new ThreadImpl(7);
ThreadImpl t4 = new ThreadImpl(1);
ThreadImpl t5 = new ThreadImpl(4);
ExecutorInterfaceWithSchedule executor = new ExecutorInterfaceWithSchedule();
executor.execute(t1);
executor.execute(t2);
executor.execute(t3);
executor.execute(t4);
executor.execute(t5);
Thread.sleep(10000);
}
}
Demo1-3執(zhí)行結(jié)果:
Thread[Thread-1,5,main]5
Thread[Thread-2,5,main]7
Thread[Thread-3,5,main]6
Thread[Thread-4,5,main]4
Thread[Thread-5,5,main]1
Graphic 1-1
與Executor有關(guān)的接口
1.3
ExecutorService接口
ExecutorService接口用于管理Executor接口,用于跟蹤一個(gè)和多個(gè)異步任務(wù)的執(zhí)行。簡(jiǎn)單的說就是提供一個(gè)線程池的功能,可以向線程池中提交多個(gè)任務(wù),線程池根據(jù)具體的實(shí)現(xiàn),采用一定的調(diào)度方法和策略對(duì)提交的線程進(jìn)行排隊(duì)和執(zhí)行。
ExecutorService提供了shutDown方法,可以終止線程池繼續(xù)接受新的任務(wù),使用shutDown方法并不會(huì)立即取消正在執(zhí)行的任務(wù),他會(huì)在線程任務(wù)執(zhí)行結(jié)束后,自動(dòng)關(guān)閉并釋放線程資源。shutDownNow方法則不同,線程池會(huì)嘗試試圖關(guān)閉正在執(zhí)行的線程。
Submit擴(kuò)展了Executor接口的executor方法,并返回一個(gè)Future,用來取消或查詢線程任務(wù)。invokeAll和invokeAny方法是批量執(zhí)行任務(wù)的常見形式。invokeAll是等待所有任務(wù)結(jié)束才返回,而invokeAny是其中有一個(gè)任務(wù)完成就返回。
一般通過Executors類的靜態(tài)函數(shù)來創(chuàng)建相應(yīng)的ExecutorService實(shí)例。
Demo 1-4中,主線程先創(chuàng)建了十個(gè)任務(wù),然后將這十個(gè)任務(wù)的集合提交給線程池執(zhí)行,線程池的大小是3,線程池根據(jù)內(nèi)部的調(diào)度策略去調(diào)度執(zhí)行任務(wù),從最終的輸出可以看出,線程池的子線程1執(zhí)行的任務(wù)最多。最終在主線程中進(jìn)行結(jié)果統(tǒng)計(jì),關(guān)閉線程池。需要注意的是,線程池的關(guān)閉需要手動(dòng)代碼,而且還要給出出錯(cuò)的情況下如何合理的終結(jié)線程池。
Demo 1-4 線程池的使用:
package com.upc.upcgrid.guan.SpecialUse.chapter01;
import java.util.ArrayList;
import java.util.List;
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;
import java.util.concurrent.TimeUnit;
public class ExecuteServiceInterface {
public static final int THREAD_SIZE = 10;
private static class onceCompute implements Callable{
private int start;
private int end;
public onceCompute(int start,int end) {
this.start = start;
this.end = end;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for(int i = start ; i < end ; i++)
{
sum += i;
}
System.err.println(Thread.currentThread());
return sum;
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException
{
ExecutorService pool =
Executors.newFixedThreadPool(3);//創(chuàng)建3個(gè)線程的線程池
List>
calls = new ArrayList>();//任務(wù)集合
for(int i = 0 ; i < THREAD_SIZE ;i++)//創(chuàng)建任務(wù)
{
calls.add(new onceCompute(i*100, (i+1)*100));
}
List>
futures = pool.invokeAll(calls);//阻塞等待任務(wù)完成
int sum = 0;
for(Future f :
futures)//匯總?cè)蝿?wù)計(jì)算結(jié)果
{
sum +=f.get();
}
System.out.println(sum);//輸出結(jié)果
//線程池的關(guān)閉策略
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
pool.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
Demo 1-4 的執(zhí)行結(jié)果:
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-3,5,main]
499500
1.4
ScheduleExecutorService
從Graphic1-1可以看出ScheduleExecutorService是繼承于ExecutorService的一個(gè)增強(qiáng)的接口。這個(gè)接口在ExecutorService接口的基礎(chǔ)上增加了四個(gè)操作,可以分為三種類型,一種類型是schedule函數(shù),用于在指定延時(shí)后創(chuàng)建一個(gè)線程執(zhí)行某項(xiàng)任務(wù),一種是scheduleAtFixedRate在指定延時(shí)后,創(chuàng)建一個(gè)周期性執(zhí)行的線程任務(wù),還有一種是scheduleWithFixedDelay,在指定延時(shí)后以一定的延時(shí)執(zhí)行線程任務(wù)。第二和第三種的區(qū)別在于,第二種計(jì)算的是周期,這個(gè)時(shí)間間隔是指定好的。第三種是延時(shí),是指從一次執(zhí)行結(jié)束,到下一次執(zhí)行開始的這段時(shí)間,這種方式將線程執(zhí)行的時(shí)間也考慮在內(nèi)。
Demo 1-5 給出了這個(gè)示例,每個(gè)1s中輸出當(dāng)前時(shí)間。
Demo1-5 定期任務(wù)
package com.upc.upcgrid.guan.SpecialUse.chapter01;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduleExecutorServiceInterface {
public static void main(String[] args) throws InterruptedException {
ScheduledExecutorServicepool =
Executors.newSingleThreadScheduledExecutor();
pool.scheduleAtFixedRate(new Runnable() {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void run() {
System.err.println(df.format(new Date()));
}
}, 1000,1000,TimeUnit.MILLISECONDS);
Thread.sleep(10000);
pool.shutdownNow();
}
}
1.5
ThreadFactory接口
這個(gè)接口用于創(chuàng)建一個(gè)新的線程,它與Executor接口的區(qū)別在于,Executor接口更強(qiáng)調(diào)的是執(zhí)行和管理一個(gè)線程,而ThreadFactory強(qiáng)調(diào)的是如何創(chuàng)建一個(gè)線程。在很多的Executor實(shí)現(xiàn)中,需要提供一個(gè)ThreadFactory實(shí)例,畢竟Executor類中使用new方法創(chuàng)建一個(gè)線程是不合理的,因?yàn)槿绻脩魧?duì)新線程的配置進(jìn)行更改,這種更改將會(huì)被延伸到Executor接口的所有實(shí)現(xiàn)子類,這不利于代碼的擴(kuò)展。ThreadFactory僅有一個(gè)方法newThread,實(shí)現(xiàn)這個(gè)方法,用于創(chuàng)建自己的線程邏輯。
Demo1-6中,ThreadFactory用來指定創(chuàng)建多線程的方式,定制多線程的創(chuàng)建方法,而Executor則更強(qiáng)調(diào)如何執(zhí)行,如何管理多線程。所以,在Executor類中應(yīng)當(dāng)有一個(gè)ThreadFactory引用,這樣在Executor類中就無需顯示使用new,并且負(fù)責(zé)與線程相關(guān)的配置,當(dāng)需要對(duì)線程的屬性進(jìn)行配置時(shí),不會(huì)影響到Executor的內(nèi)部實(shí)現(xiàn)。
ThreadFactory主要使用的是設(shè)計(jì)模式中的工廠方法模式,可以參考設(shè)計(jì)模式的相應(yīng)章節(jié)。
Demo1-6
ThreadFactory與Executor的關(guān)系
package com.upc.upcgrid.guan.SpecialUse.chapter01;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
public class ThreadFactoryInterface {
private static class ExecutorImp implements Executor{
private static ThreadFactory threadFactory;
@SuppressWarnings("unused")
public ExecutorImp() {
threadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
};
}
@SuppressWarnings("static-access")
public ExecutorImp(ThreadFactory tf){
this.threadFactory = tf;
}
@Override
public void execute(Runnable command) {
Thread t = threadFactory.newThread(command);
t.start();
}
}
private static class ThreadFacotoryImp implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(false);
t.setPriority(7);
return t;
}
}
public static void main(String[] args) {
Executor executor = new ExecutorImp(new ThreadFacotoryImp());
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
}
});
}
}
總結(jié)
以上是生活随笔為你收集整理的java执行程序默认多线程吗_Java多线程 执行程序(1)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络命令使用
- 下一篇: java美元兑换,(Java实现) 美元