java并行流 阻塞主线程_多线程入门案例与java8的并行流
java8 實(shí)例請移步https://www.cnblogs.com/ngLee/p/14021859.html
進(jìn)程與線程
進(jìn)程是所有線程的集合,每一個線程是進(jìn)程中的一條執(zhí)行路徑。
多線程的創(chuàng)建方式,繼承Thread\實(shí)現(xiàn)Runable
/**
* 第一種創(chuàng)建線程的方式,繼承Thread
*/
public class MultiThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"....."+i);
}
}
}
/**
* 第二種,實(shí)現(xiàn)Runnable接口,更易于擴(kuò)展。(多實(shí)現(xiàn),單繼承)
*/
public class MultiThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}
/**
* 測試類
*/
public class TestThread {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"---開始");
//1.多線程創(chuàng)建 繼承Thread
MultiThread multiThread = new MultiThread();
Thread thread = new Thread(multiThread,"線程繼承Thread-1");
Thread thread2 = new Thread(multiThread,"線程繼承Thread-2");
//2.啟動多線程調(diào)用的是start(),而不是run()
thread.start();
thread2.start();
//3.打印效果 當(dāng)前線程:線程1
/**********************************/
//2 實(shí)現(xiàn)Runnable
Runnable runnable = new MultiThread2();
Thread thread3 = new Thread(runnable,"線程實(shí)現(xiàn)Runnable-1");
Thread thread4 = new Thread(runnable,"線程實(shí)現(xiàn)Runnable-2");
thread3.start();
thread4.start();
//3 匿名內(nèi)部類的方式
Thread thread5 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName()+"匿名內(nèi)部類----"+i);
}
}
});
thread5.start();
System.out.println(Thread.currentThread().getName()+"---結(jié)束");
}
}
效果展示:并不是按照自上而下的執(zhí)行
線程的幾個狀態(tài)
新建狀態(tài):當(dāng)用new操作符創(chuàng)建一個線程時(shí), 例如new Thread(r),線程還沒有開始運(yùn)行,此時(shí)線程處在新建狀態(tài)。 當(dāng)一個線程處于新生狀態(tài)時(shí),程序還沒有開始運(yùn)行線程中的代碼。
就緒狀態(tài):一個新創(chuàng)建的線程并不自動開始運(yùn)行,要執(zhí)行線程,必須調(diào)用線程的start()方法。當(dāng)線程對象調(diào)用start()方法即啟動了線程,start()方法創(chuàng)建線程運(yùn)行的系統(tǒng)資源,并調(diào)度線程運(yùn)行run()方法。當(dāng)start()方法返回后,線程就處于就緒狀態(tài)。處于就緒狀態(tài)的線程并不一定立即運(yùn)行run()方法,線程還必須同其他線程競爭CPU時(shí)間,只有獲得CPU時(shí)間才可以運(yùn)行線程。因?yàn)樵趩蜟PU的計(jì)算機(jī)系統(tǒng)中,不可能同時(shí)運(yùn)行多個線程,一個時(shí)刻僅有一個線程處于運(yùn)行狀態(tài)。因此此時(shí)可能有多個線程處于就緒狀態(tài)。對多個處于就緒狀態(tài)的線程是由Java運(yùn)行時(shí)系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度的。
運(yùn)行狀態(tài):當(dāng)線程獲得CPU時(shí)間后,它才進(jìn)入運(yùn)行狀態(tài),真正開始執(zhí)行run()方法。
阻塞狀態(tài):?線程運(yùn)行過程中,可能由于各種原因進(jìn)入阻塞狀態(tài):
1>線程通過調(diào)用sleep方法進(jìn)入睡眠狀態(tài);
2>線程調(diào)用一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調(diào)用者;
3>線程試圖得到一個鎖,而該鎖正被其他線程持有;
4>線程在等待某個觸發(fā)條件;
死亡狀態(tài):有兩個原因會導(dǎo)致線程死亡:1)run方法正常退出而自然死亡,2)一個未捕獲的異常終止了run方法而使線程猝死。為了確定線程在當(dāng)前是否存活著(就是要么是可運(yùn)行的,要么是被阻塞了),需要使用isAlive方法。如果是可運(yùn)行或被阻塞,這個方法返回true; 如果線程仍舊是new狀態(tài)且不是可運(yùn)行的, 或者線程死亡了,則返回false.
簡單需求:目前螞蟻課堂有10萬個用戶,現(xiàn)在螞蟻課堂需要做活動,給每一個用戶發(fā)送一條祝福短信
/**
* 提交實(shí)體
*/
public class UserThread extends Thread {
private List uList;
public UserThread(List uList){
this.uList = uList;
}
public List getuList() {
return uList;
}
public void setuList(List uList) {
this.uList = uList;
}
@Override
public void run() {
uList.stream().forEach(userEntity -> {
System.out.println("threadName:" + Thread.currentThread().getName() + "-用戶記錄序號:" + userEntity.getUno()
+ "---用戶名稱:" + userEntity.getUname());
//短信發(fā)送接口
});
}
}
/**
* 測試類
*/
public class TestThread {
public static void main(String[] args) {
//所有記錄
List list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
UserEntity userEntity = new UserEntity();
userEntity.setUno("用戶id"+i);
userEntity.setUname("用戶名字"+i);
list.add(userEntity);
}
//將數(shù)據(jù)進(jìn)行分割,每組四千,這個每組數(shù)據(jù)量最好取配置,使用高峰期調(diào)低,保證不會超時(shí)
int everyNum = 20;
List> lists= spiltList(list,everyNum);
for (int i = 0; i < lists.size(); i++) {
Thread th = new UserThread(lists.get(i));
th.start();
}
//第二種java8 并行流,底層:ForkJoin --todo
//使用并行流的時(shí)候,最好不要修改數(shù)據(jù),如果需要map里的返回值,則用Collectors進(jìn)行收集,不要foreach里用list.add()
lists.parallelStream().forEach( lst -> {
lst.parallelStream().forEach( userEntity -> {
System.out.println("threadName:" + Thread.currentThread().getName() + "-用戶記錄序號:" + userEntity.getUno()
+ "---用戶名稱:" + userEntity.getUname());
});
});
}
private static List> spiltList(List list, int everyNum) {
//總數(shù)據(jù)量
int total = list.size();
//分組數(shù)量
int group = total%everyNum == 0 ? total/everyNum : total/everyNum +1 ;
//java8 stream
List userList = Stream.iterate(0, n->n+1).
limit(group).parallel().
map(seed -> {
List list1 = list.stream().skip(seed * everyNum).limit(everyNum).
collect(Collectors.toList());
return list1;
}
).collect(ArrayList::new,ArrayList::add,List::addAll);
return userList;
}
}
打印效果如圖,不是按順序打印,但這不正好就是多線程需要的效果的了嗎?
總結(jié)
以上是生活随笔為你收集整理的java并行流 阻塞主线程_多线程入门案例与java8的并行流的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 储蓄国债快要发行了,你准备好资金了吗?
- 下一篇: java pojo 是什么_什么是POJ