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