java线程触发_java线程
線程.
狀態(tài)
新建狀態(tài)(New):
當(dāng)用 new 操作符創(chuàng)建一個(gè)線程時(shí), 例如 new Thread(r),線程還沒有開始運(yùn)行,此時(shí)
線程處在新建狀態(tài)。 當(dāng)一個(gè)線程處于新生狀態(tài)時(shí),程序還沒有開始運(yùn)行線程中的代碼
就緒狀態(tài)(Runnable)
一個(gè)新創(chuàng)建的線程并不自動(dòng)開始運(yùn)行,要執(zhí)行線程,必須調(diào)用線程的 start()方法。當(dāng)線
程對(duì)象調(diào)用 start()方法即啟動(dòng)了線程,start()方法創(chuàng)建線程運(yùn)行的系統(tǒng)資源,并調(diào)度線程運(yùn)行
run()方法。當(dāng) start()方法返回后,線程就處于就緒狀態(tài)。
處于就緒狀態(tài)的線程并不一定立即運(yùn)行 run()方法,線程還必須同其他線程競(jìng)爭(zhēng) CPU 時(shí)
間,只有獲得 CPU 時(shí)間才可以運(yùn)行線程。因?yàn)樵趩?CPU 的計(jì)算機(jī)系統(tǒng)中,不可能同時(shí)運(yùn)行
多個(gè)線程,一個(gè)時(shí)刻僅有一個(gè)線程處于運(yùn)行狀態(tài)。因此此時(shí)可能有多個(gè)線程處于就緒狀態(tài)。
對(duì)多個(gè)處于就緒狀態(tài)的線程是由 Java 運(yùn)行時(shí)系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度
的。
運(yùn)行狀態(tài)(Running)
當(dāng)線程獲得 CPU 時(shí)間后,它才進(jìn)入運(yùn)行狀態(tài),真正開始執(zhí)行 run()方法.
阻塞狀態(tài)(Blocked)
線程運(yùn)行過程中,可能由于各種原因進(jìn)入阻塞狀態(tài):
1>線程通過調(diào)用 sleep 方法進(jìn)入睡眠狀態(tài);
2>線程調(diào)用一個(gè)在 I/O 上被阻塞的操作,即該操作在輸入輸出操作完成之前不會(huì)返回
到它的調(diào)用者;
3>線程試圖得到一個(gè)鎖,而該鎖正被其他線程持有;
4>線程在等待某個(gè)觸發(fā)條件;
......
所謂阻塞狀態(tài)是正在運(yùn)行的線程沒有運(yùn)行結(jié)束,暫時(shí)讓出 CPU,這時(shí)其他處于就緒狀
態(tài)的線程就可以獲得 CPU 時(shí)間,進(jìn)入運(yùn)行狀態(tài)。
死亡狀態(tài)(Dead)
有兩個(gè)原因會(huì)導(dǎo)致線程死亡:
run 方法正常退出而自然死亡,
一個(gè)未捕獲的異常終止了 run 方法而使線程猝死。
為了確定線程在當(dāng)前是否存活著(就是要么是可運(yùn)行的,要么是被阻塞了),需要使
用 isAlive 方法。如果是可運(yùn)行或被阻塞,這個(gè)方法返回 true; 如果線程仍舊是 new 狀態(tài)
且不是可運(yùn)行的, 或者線程死亡了,則返回 false
新建線程的方法:
1.繼承Thread類實(shí)現(xiàn)多線程
run()為線程類的核心方法,相當(dāng)于主線程的main方法,是每個(gè)線程的入口
一個(gè)線程調(diào)用 兩次start()方法將會(huì)拋出線程狀態(tài)異常,也就是的start()只可以被調(diào)用一次
class Thread1 extends Thread{
@Override
public void run() {
//迭代 循環(huán)
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"__"+i);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
System.out.println("main start: "+Thread.currentThread().getName());
for (int i = 0; i < 10; i++) {
Thread1 thread1 =new Thread1();
thread1.start();//多個(gè)跑道 并行
}
//main 不等了
System.out.println(" main end ");
}
}
2通過Runnable接口創(chuàng)建線程類
定義runnable接口的實(shí)現(xiàn)類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執(zhí)行體。
創(chuàng)建 Runnable實(shí)現(xiàn)類的實(shí)例,并以此實(shí)例作為Thread的target來創(chuàng)建Thread對(duì)象,該Thread對(duì)象才是真正的線程對(duì)象。
調(diào)用線程對(duì)象的start()方法來啟動(dòng)該線程。
public class RunnableThreadTest implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "__" + i);
}
}
public static void main(String[] args) {
System.out.println("main start: "+Thread.currentThread().getName());
for (int i = 0; i < 5; i++) {
RunnableThreadTest runnableThreadTest = new RunnableThreadTest();
new Thread(runnableThreadTest,"線程"+i).start();
}
}
}
通過Callable和Future創(chuàng)建線程
創(chuàng)建Callable接口的實(shí)現(xiàn)類,并實(shí)現(xiàn)call()方法,該call()方法將作為線程執(zhí)行體,并且有返回值。
public interface Callable
{
V call() throws Exception;
}
創(chuàng)建Callable實(shí)現(xiàn)類的實(shí)例,使用FutureTask類來包裝Callable對(duì)象,該FutureTask對(duì)象封裝了該Callable對(duì)象的call()方法的返回值。(FutureTask是一個(gè)包裝器,它通過接受Callable來創(chuàng)建,它同時(shí)實(shí)現(xiàn)了Future和Runnable接口。)
使用FutureTask對(duì)象作為Thread對(duì)象的target創(chuàng)建并啟動(dòng)新線程。
調(diào)用FutureTask對(duì)象的get()方法來獲得子線程執(zhí)行結(jié)束后的返回值
public class CallableThreadTest implements Callable
{
public static void main(String[] args)
{
CallableThreadTest ctt = new CallableThreadTest();
FutureTask ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++)
{
log.info(Thread.currentThread().getName()+" 的循環(huán)變量i的值"+i);
if(i==20)
{
new Thread(ft,"有返回值的線程").start();
}
}
try
{
log.info("子線程的返回值:"+ft.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
log.info(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
并行參數(shù)問題的解決
ThreadLocal (線程本地變量) map
新建ThreadLocal并重寫initialValue() 重寫initialValue 方法 否者對(duì)象為空
調(diào)用方法(ThreadLocal定義的變量名)threadLocal.get();
package com.testfan.thread;
import java.util.HashMap;
import java.util.Map;
public class ThreadLocalMapTest {
static ThreadLocal> threadLocal = new ThreadLocal>(){
@Override
protected Map initialValue() {
return new HashMap();
}
};
public static void main(String[] args) {
threadLocal.get().put("1","11");
dosomethings();
new Thread(new Runnable() {
@Override
public void run() {
threadLocal.get().put("1","22");
dosomethings();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
threadLocal.get().put("1","33");
dosomethings();
}
}).start();
}
private static void dosomethings() {
System.out.println(Thread.currentThread().getName() + " " +threadLocal.get());
}
}
線程等待問題
線程等待 join
for (int i = 0; i < 10; i++) {
Thread1 thread1 =new Thread1();
thread1.start();//多個(gè)跑道 并行
try {
thread1.join();//線程等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sleep
public static void main(String[] args) {
System.out.println("main start: "+Thread.currentThread().getName());
for (int i = 0; i < 10; i++) {
Thread1 thread1 =new Thread1();
thread1.start();//多個(gè)跑道 并行
try {
thread1.sleep(1);;//線程等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
線程計(jì)數(shù)器
public class ThreadDemo2 {
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch= new CountDownLatch(5);//使用java并發(fā)庫(kù)concurrent
//啟用5個(gè)線程
for(int i=1;i<=5;i++){
new Thread(new Runnable(){
public void run(){
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("子線程執(zhí)行!");
latch.countDown();//讓latch中的數(shù)值減一
}
}).start();
}
//主線程
latch.await();//阻塞當(dāng)前線程直到latch中數(shù)值為零才執(zhí)行
System.out.println("主線程執(zhí)行!");
}
}
countDownLatch不可能重新初始化或者修改CountDownLatch對(duì)象內(nèi)部計(jì)數(shù)器的值,一個(gè)線程調(diào)用countdown方法happen-before另外一個(gè)線程調(diào)用await方法
線程池優(yōu)化
為什么用線程池:
服務(wù)器應(yīng)用程序中經(jīng)常出現(xiàn)的情況是:單個(gè)任務(wù)處理的時(shí)間很短而請(qǐng)求的數(shù)目卻是巨大的。
為每個(gè)請(qǐng)求創(chuàng)建一個(gè)新線程的開銷很大;為每個(gè)請(qǐng)求創(chuàng)建新線程的服務(wù)器在創(chuàng)建和銷毀線程上花費(fèi)的時(shí)間和消耗的系統(tǒng)資源要比花在處理實(shí)際的用戶請(qǐng)求的時(shí)間和資源更多。
線程池為線程生命周期開銷問題和資源不足問題提供了解決方案
好處:
在請(qǐng)求到達(dá)時(shí)線程已經(jīng)存在,所以無意中也消除了線程創(chuàng)建所帶來的延遲。這樣,就可以立即為請(qǐng)求服務(wù),使應(yīng)用程序響應(yīng)更快。而且,通過適當(dāng)?shù)卣{(diào)整線程池中的線程數(shù)目,也就是當(dāng)請(qǐng)求的數(shù)目超過某個(gè)閾值時(shí),就強(qiáng)制其它任何新到的請(qǐng)求一直等待,直到獲得一個(gè)線程來處理為止,從而可以防止資源不足。
線程池的幾種方法:
https://www.cnblogs.com/aaron911/p/6213808.html
第一種:定時(shí)任務(wù)(jenkines的定時(shí)任務(wù))
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
實(shí)例:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("111111");
}
},0,1,TimeUnit.SECONDS);//0代表延時(shí)多久 1代表多久執(zhí)行一次,TimeUnit.SECONDS代表時(shí)間單位
第二種:
//可以最大開65536, 短任務(wù)
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
實(shí)例:
for (int i = 0; i < 100000; i++) {
final int index = i;
//放了十個(gè)線程
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index+Thread.currentThread().getName());
}
});
}
fixedThreadPool.shutdown();
第三種:
//按照固定的數(shù)目
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);//一次運(yùn)行3個(gè)
實(shí)例:
for (int i = 0; i < 100; i++) {
final int index = i;
//放了十個(gè)線程
fixedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index+Thread.currentThread().getName());
}
});
}
fixedThreadPool.shutdown();
第四種:
//默認(rèn)一個(gè)
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
實(shí)例:
for (int i = 0; i < 100; i++) {
final int index = i;
//放了十個(gè)線程
singleThreadExecutor.execute(new Runnable() {
public void run() {
System.out.println(index+Thread.currentThread().getName());
}
});
}
fixedThreadPool.shutdown();
總結(jié)
以上是生活随笔為你收集整理的java线程触发_java线程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 李宁多少钱啊?
- 下一篇: mysql数据库是一个软件呐_15款好用