亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文精通Java 多線程之全方位解讀

 更新時(shí)間:2021年10月12日 10:44:43   作者:青素i  
Java 給多線程編程提供了內(nèi)置的支持。 一條線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線程并行執(zhí)行不同的任務(wù),多線程是多任務(wù)的一種特別的形式,但多線程使用了更小的資源開銷

并行和并發(fā)

并行:多個(gè)CPU實(shí)例或是多臺(tái)機(jī)器同時(shí)執(zhí)行一段處理邏輯,是真正的同時(shí)。
并發(fā):一個(gè)CPU或一臺(tái)機(jī)器,通過CPU調(diào)度算法,讓用戶看上去同時(shí)去執(zhí)行,實(shí)際上從CPU操作層面并不是真正的同時(shí)。并發(fā)往往需要公共的資源,對(duì)公共資源的處理和線程之間的協(xié)調(diào)是并發(fā)的難點(diǎn)。

線程基礎(chǔ)概念

線程和進(jìn)程

進(jìn)程就是程序,有獨(dú)立的運(yùn)行內(nèi)存空間,比如應(yīng)用和后臺(tái)服務(wù),windows是一個(gè)支持多進(jìn)程的操作系統(tǒng)。內(nèi)存越大能同時(shí)運(yùn)行的程序越多,在Java里一個(gè)進(jìn)程指的是一個(gè)運(yùn)行在獨(dú)立JVM的程序。
線程:一個(gè)程序里運(yùn)行的多個(gè)任務(wù),每個(gè)任務(wù)就是一個(gè)線程,線程是共享內(nèi)存的在QQ、微信、釘釘?shù)溶浖忻總€(gè)聊天窗口都是一個(gè)線程,可以同時(shí)接收消息和發(fā)送消息,但只有一個(gè)內(nèi)存占用。

多線程的好處

◆ 同時(shí)運(yùn)行多個(gè)任務(wù),提升CPU的使用效率
◆ 共享內(nèi)存,占用資源更少,線程間可以通信
◆ 異步調(diào)用,避免阻塞
◆ 用戶體驗(yàn)感更好

線程的狀態(tài)

線程包括5種狀態(tài):
1、新建(New):線程對(duì)象被創(chuàng)建時(shí),它只會(huì)短暫地處于這種狀態(tài)。此時(shí)它已經(jīng)分配了必須的系統(tǒng)資源,并執(zhí)行了初始化。例如,Thread thread = new Thread()。
2、就緒(Runnable):稱為“可執(zhí)行狀態(tài)”。線程對(duì)象被創(chuàng)建后,其它線程調(diào)用了該對(duì)象的start()方法,從而來啟動(dòng)該線程。例如,thread.start()。處于就緒狀態(tài)的線程,隨時(shí)可能被CPU調(diào)度執(zhí)行。
3、運(yùn)行(Running):線程獲取CPU權(quán)限進(jìn)行執(zhí)行。注意:線程只能從就緒狀態(tài)進(jìn)入運(yùn)行狀態(tài)。
4、阻塞(Blocked):阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行。直到線程進(jìn)入就緒狀態(tài),才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)。阻塞的情況分為三種:
(1)等待阻塞:通過調(diào)用線程的wait()方法,讓線程等待某工作的完成。
(2)同步阻塞:線程在獲取synchronized同步鎖失?。ㄒ?yàn)殒i被其他線程占用),它會(huì)進(jìn)入同步阻塞狀態(tài)。
(3)其他阻塞:通過調(diào)用線程的sleep()或發(fā)出了I/O請(qǐng)求時(shí),線程會(huì)進(jìn)入到阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或是超時(shí)?;蚴荌/O處理完畢時(shí),線程重新轉(zhuǎn)入就緒狀態(tài)。
5.死亡(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。

在這里插入圖片描述

實(shí)現(xiàn)多線程的兩種方式

繼承Thread類

第一步 繼承Therad父類
第二步 重寫run方法
第三步 實(shí)例化線程類
第四步 啟動(dòng)線程

public class ThreadDemo extends Thread{
	
	

	/**
	 * 繼承Thread
	 * 
	 * @author gavin
	 *
	 */
	
	@Override
	public void run() {
		// TODO 自動(dòng)生成的方法存根
		//打印10次世界
			try {
				for(int i=0;i<10;i++) {
					System.out.print("世界");
					Thread.sleep(200);//阻塞態(tài) 休息200毫秒
				}		
		} catch (InterruptedException e) {
			// TODO 自動(dòng)生成的 catch 塊
			e.printStackTrace();
		}
		System.out.println("線程執(zhí)行完成!");				
	}
	
	
	public static void main(String[] args) {
		
		//初始化線程t1 t2
		ThreadDemo t1 = new ThreadDemo();
		ThreadDemo t2 = new ThreadDemo();
		//啟動(dòng)線程
		t1.start();
		t2.start();
		//注意不是調(diào)用run方法 而是啟動(dòng)線程 調(diào)用run方法只是執(zhí)行了run方法但不是多線程執(zhí)行
		
		//打印200次你好
		for(int i = 0;i<20;i++) {
			System.out.print("你好");
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO 自動(dòng)生成的 catch 塊
				e.printStackTrace();
			}
		}
		
		//結(jié)束態(tài)
		System.out.println("程序運(yùn)行完成");
		
		
		
		
	}
	
	
	
	

}

在這里插入圖片描述

在這里插入圖片描述

注意:多線程每次運(yùn)行得到的結(jié)果是不相同的
Thread.sleep();方法可以使線程阻塞
調(diào)用start();方法才能啟動(dòng)多線程
調(diào)用run方法和普通方法效果相同

實(shí)現(xiàn)Runnable接口

第一步 實(shí)現(xiàn)Runnable接口
第二步 重寫run方法
第三步 實(shí)例化當(dāng)前類(任務(wù)類)
第四步 將任務(wù)類對(duì)象作為參數(shù)傳入Thread中進(jìn)行實(shí)列化
第五步 啟動(dòng)多線程

/**
 * 實(shí)現(xiàn)二: 實(shí)現(xiàn)Runnable接口
 * 當(dāng)類本身有父類的時(shí)候 使用實(shí)現(xiàn)Runnable接口
 * @author gavin
 *
 */
public class RunnableDemo implements Runnable {

	@Override
	public void run() {
		// TODO 自動(dòng)生成的方法存根
		//打印10次世界
		try {
			for(int i=0;i<10;i++) {
				System.out.print(Thread.currentThread().getName()+"世界\t");
				if(i%3==0) {
					System.out.println();
				}
				Thread.sleep(200);//阻塞態(tài) 休息200毫秒
			}		
	} catch (InterruptedException e) {
		// TODO 自動(dòng)生成的 catch 塊
		e.printStackTrace();
	}
	System.out.println(Thread.currentThread().getName()+"線程執(zhí)行完成!");			
		
	}
	
	public static void main(String[] args) {
		
		//實(shí)列化當(dāng)前類 
		RunnableDemo runnableDemo1 = new RunnableDemo();
		
		//創(chuàng)建線程 傳入任務(wù)類
		Thread t1 = new Thread(runnableDemo1);
		Thread t2 = new Thread(runnableDemo1);
		Thread t3 = new Thread(runnableDemo1);
			
		//設(shè)置線程優(yōu)先級(jí)
		t1.setPriority(Thread.MAX_PRIORITY);//最高優(yōu)先級(jí)
		t2.setPriority(Thread.MIN_PRIORITY);//最低優(yōu)先級(jí)
		t3.setPriority(5);//設(shè)置默認(rèn)優(yōu)先級(jí) 優(yōu)先級(jí)為5 優(yōu)先級(jí)從0-10最高為10
		
		//啟動(dòng)線程
		t1.start();
		t2.start();
		t3.start();
		
		
	}	

}

在這里插入圖片描述

在這里插入圖片描述

注意 setPriority 可以設(shè)置線程的優(yōu)先級(jí)
但并不代表線程一定優(yōu)先執(zhí)行完

線程的安全性和原子性

由于線程之間可以共享內(nèi)存,則某個(gè)對(duì)象(變量)是可以被多個(gè)線程共享的,是可以被多個(gè)線程同時(shí)訪問的。當(dāng)多個(gè)線程訪問某個(gè)類時(shí),不管運(yùn)行時(shí)環(huán)境采用何種調(diào)度方式或者這些進(jìn)程將如何交替執(zhí)行,并且在主調(diào)代碼中不需要任何額外的同步或協(xié)同,這個(gè)類都能表現(xiàn)出正確的行為,那么就稱這個(gè)類是線程安全的。
舉個(gè)栗子:甲乙兩個(gè)人,甲負(fù)責(zé)向筐里放蘋果,乙負(fù)責(zé)從筐里數(shù)蘋果,甲乙同時(shí)進(jìn)行,問乙如何操作才能正確?
不幸的是,以上代碼不是線程安全的,因?yàn)閏ount++并非是原子操作,實(shí)際上,它包含了三個(gè)獨(dú)立的操作:讀取count的值,將值加1,然后將計(jì)算結(jié)果寫入count。如果線程A讀到count為10,馬上線程B讀到count也為10,線程A加1寫入后為11,線程B由于已經(jīng)讀過count值為10,執(zhí)行加1寫入后依然為11,這樣就丟失了一次計(jì)數(shù)。在并發(fā)編程中,這種由于不恰當(dāng)?shù)膱?zhí)行時(shí)序而出現(xiàn)不正確的結(jié)果是一種非常重要的情況,它有一個(gè)正式的名字:
競(jìng)態(tài)條件(Race Condition)。

Java 內(nèi)存模型中的可見性、原子性和有序性。
可見性:當(dāng)多個(gè)線程訪問同一個(gè)變量x時(shí),線程1修改了變量x的值,線程1、線程2…線程n能夠立即讀
取到線程1修改后的值。
有序性:即程序執(zhí)行時(shí)按照代碼書寫的先后順序執(zhí)行。在Java內(nèi)存模型中,允許編譯器和處理器對(duì)指
令進(jìn)行重排序,但是重排序過程不會(huì)影響到單線程程序的執(zhí)行,卻會(huì)影響到多線程并發(fā)執(zhí)行的正確性。
原子性:原子性通常指多個(gè)操作不存在只執(zhí)行一部分的情況,要么全部執(zhí)行、要么全部不執(zhí)行。

鎖的概念和使用

竟態(tài)條件會(huì)使運(yùn)行結(jié)果變得不可靠,程序的運(yùn)行結(jié)果取決于方法的調(diào)用順序,將方法以串行的
方式來訪問,我們稱這種方式為同步鎖(synchronized)。
Java實(shí)現(xiàn)同步鎖的方式有:
▶同步方法synchronized method
▶ 同步代碼塊 synchronized(Lock)
▶ 等待與喚醒 wait 和 notify
▶ 使用特殊域變量(volatile)實(shí)現(xiàn)線程同步
▶ 使用重入鎖實(shí)現(xiàn)線程同步ReentrantLock
▶ 使用局部變量實(shí)現(xiàn)線程同步ThreadLocal
synchronized
synchronized是Java 的內(nèi)置鎖機(jī)制,是在JVM上的
可以同步代碼塊,也可以同步方法
//同步代碼塊

synchronized(object){
}

//同步方法

public synchronized void method() {
// do something
}

注:同步是一種高開銷的操作,因此應(yīng)該盡量減少同步的內(nèi)容。通常沒有必要同步整個(gè)方法。

ReentrantLock
可重入鎖,是一種顯示鎖,在JavaSE5.0中新增了一個(gè)java.util.concurrent包來支持同步。
ReentrantLock類是可重入、互斥、實(shí)現(xiàn)了Lock接口的鎖,它與使用synchronized方法和快具有相同
的基本行為和語義,并且擴(kuò)展了其能力。
ReentrantLock() : 創(chuàng)建一個(gè)ReentrantLock實(shí)例
lock() : 獲得鎖
unlock() : 釋放鎖
可重入: 甲獲得鎖后釋放鎖或鎖失效,乙可繼續(xù)獲得這個(gè)鎖

生產(chǎn)消費(fèi)者模型

生產(chǎn)消費(fèi)者模型是一個(gè)非常典型的多線程并發(fā)處理的模型,在實(shí)際的生產(chǎn)應(yīng)用中也有非常廣泛的使用。

在這里插入圖片描述

生產(chǎn)消費(fèi)者模型中的類–存儲(chǔ)類

import java.util.LinkedList;

public class Store {
	
	
	/*
	 * 存儲(chǔ) 隊(duì)列實(shí)現(xiàn) 
	 * 
	 * @author gavin
	 * */
	
	//創(chuàng)建隊(duì)列
	LinkedList<Integer> list = new LinkedList<Integer>();
	
	//設(shè)置最大存儲(chǔ)值
	int max = 10;
	
	//生產(chǎn)者生產(chǎn) 放入隊(duì)尾
	public void push(int n) {
		
		synchronized(list) {
			try {
				if(list.size()>=max){
						System.out.println("存滿了");				
					    //線程掛起	
						list.wait();
					}else {
						//隊(duì)列沒有存滿 繼續(xù)存
						System.out.println("存入:"+n);
						list.add(n);
						//放完之后必須有 因此喚醒取的線程  
						list.notifyAll();					
					}
				
				
			}catch (Exception e) {
					// TODO 自動(dòng)生成的 catch 塊
					e.printStackTrace();
				}				
		}
		
		
	}
	
	
	//消費(fèi)者消費(fèi) 從隊(duì)頭取出
	public int pop() {
		try {
			synchronized(list){
				if(list.size()<=0) {
					System.out.println("隊(duì)列空了。。。。");
					//空了之后就不能取了 因此線程掛起
					list.wait();
				}else {
					//從對(duì)頭取出
					int n = list.poll();
					System.out.println("取出:"+n);
					//取出了就一定不會(huì)滿 因此要喚醒線程
					list.notifyAll();
					return n;
					
				}								
			}
						
		}catch (Exception e) {
			// TODO: handle exception
		}	
		
		return 0;
	}
	
	
	
	
	
	
	
	
	

}

生產(chǎn)消費(fèi)者模型中的類–生產(chǎn)者

/**
 * 生產(chǎn)者
 */

public class Producer  implements Runnable{

	private Store store;
	
	public Producer(Store store) {
		// TODO 自動(dòng)生成的構(gòu)造函數(shù)存根
		this.store = store;
	}
	
	
	@Override
	public void run() {
		// TODO 自動(dòng)生成的方法存根
		try {
			//生產(chǎn)需要事件 休息100毫秒再生產(chǎn)
			Thread.sleep(100);
			//產(chǎn)生隨機(jī)數(shù)字
			store.push((int)(Math.random()*100));
		}catch (Exception e) {
			// TODO: handle exception
			
		}
		
			
	}
	

}

生產(chǎn)消費(fèi)者模型中的類–消費(fèi)者

public class Customer implements Runnable{

	
	private Store store;
	
	public Customer(Store store) {
		// TODO 自動(dòng)生成的構(gòu)造函數(shù)存根
		this.store = store;
	}
	
	

	@Override
	public void run() {
		// TODO 自動(dòng)生成的方法存根
		try {
			//消費(fèi)者消費(fèi)需要時(shí)間 休息200毫秒
			Thread.sleep(200);
			//從隊(duì)頭取出
			store.pop();
		}catch (Exception e) {
			// TODO: handle exception
		}
	}

}

測(cè)試類

package com.qingsu.pcm;

public class TestPcm {

	public static void main(String[] args) {
		Store store = new Store();
		
		while(true) {
			Producer producer = new Producer(store);
			Customer customer = new Customer(store);
			
			Thread t1 = new Thread(producer);
			Thread t2 = new Thread(customer);
			
			t1.start();
			t2.start();
			
		}
		
	}
	
	
}

效果

在這里插入圖片描述

volatile變量

volatile具有可見性、有序性,不具備原子性。
我們了解到synchronized是阻塞式同步,稱為重量級(jí)鎖。
而volatile是非阻塞式同步,稱為輕量級(jí)鎖。
被volatile修飾的變量能夠保證每個(gè)線程能夠獲取該變量的最新值,
從而避免出現(xiàn)數(shù)據(jù)臟讀的現(xiàn)象。

線程池的概念和使用

線程的創(chuàng)建是比較消耗內(nèi)存的,所以我們要事先創(chuàng)建若干個(gè)可執(zhí)行的線程放進(jìn)一個(gè)“池(容器)”里面,需要的時(shí)候就直接從池里面取出來不需要自己創(chuàng)建,使用完畢也不需要銷毀而是放進(jìn)“池”中,從而減少了創(chuàng)建和銷毀對(duì)象所產(chǎn)生的開銷。

ExecutorService:線程池接口
ExecutorService pool(池名稱) = Executors.常用線程池名;

常用線程池:
newsingleThreadExecutor :單個(gè)線程的線程池,即線程池中每次只有一個(gè)線程在工作,單線程串行執(zhí)行任務(wù)
newfixedThreadExecutor(n):固定數(shù)量的線程池,每提交一個(gè)任務(wù)就是一個(gè)線程,直到達(dá)到線程池的最大數(shù)量,然后在后面等待隊(duì)列前面的線程執(zhí)行或者銷毀()。該方式一般會(huì)使線程具有一定的執(zhí)行順序
newCacheThreadExecutor:一個(gè)可緩存的線程池。當(dāng)線程池超過了處理任務(wù)所需要的線程數(shù),那么就會(huì)回收部分閑置線程(一般是閑置60s)。當(dāng)有任務(wù)來時(shí)而線程不夠時(shí),線程池又會(huì)創(chuàng)建新的線程,當(dāng)線程夠時(shí)就調(diào)用池中線程。適
用于大量的耗時(shí)較少的線程任務(wù)。
newScheduleThreadExecutor:一個(gè)大小無限的線程池,該線程池多用于執(zhí)行延遲任務(wù)或者固定周期的任務(wù)。

示例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPcmTwo {
		
/*
 * 利用線程池創(chuàng)建線程
*/
	
	
	public static void main(String[] args) {
		Store store = new Store();
		
		


		//創(chuàng)建10個(gè)線程的線程池
		ExecutorService service = Executors.newFixedThreadPool(10);
		ExecutorService serviceTwo = Executors.newFixedThreadPool(10);
		
		//創(chuàng)建可緩存的線程池
		//可緩存的
		//ExecutorService service = Executors.newCachedThreadPool();
		//ExecutorService serviceTwo = Executors.newCachedThreadPool();
		
		for(int i =0 ;i<11;i++) {
			service.execute(new Producer(store));
			
		}
		for(int i =0 ;i<11;i++) {
			serviceTwo.execute(new Customer(store));			
		}
			
		
		
		
		//關(guān)閉線程池
			service.shutdown();
			serviceTwo.shutdown();	
	}

}

在這里插入圖片描述

到此這篇關(guān)于一文精通Java 多線程之全方位解讀的文章就介紹到這了,更多相關(guān)Java 多線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloud微服務(wù)架構(gòu)實(shí)戰(zhàn)之微服務(wù)治理功能的實(shí)現(xiàn)

    SpringCloud微服務(wù)架構(gòu)實(shí)戰(zhàn)之微服務(wù)治理功能的實(shí)現(xiàn)

    這篇文章主要介紹了SpringCloud微服務(wù)架構(gòu)實(shí)戰(zhàn)之微服務(wù)治理,這些治理工具主要包括服務(wù)的注冊(cè)與發(fā)現(xiàn)、負(fù)載均衡管理、動(dòng)態(tài)路由、服務(wù)降級(jí)和故障轉(zhuǎn)移、鏈路跟蹤、服務(wù)監(jiān)控等,需要的朋友可以參考下
    2022-02-02
  • Java中的接口知識(shí)匯總

    Java中的接口知識(shí)匯總

    本文給大家匯總介紹了在java中的接口知識(shí),包括為什么要使用接口、什么是接口、抽象類和接口的區(qū)別、如何定義接口以及定義接口注意點(diǎn),希望大家能夠喜歡
    2016-04-04
  • 使用IDEA配置Tomcat和連接MySQL數(shù)據(jù)庫(JDBC)詳細(xì)步驟

    使用IDEA配置Tomcat和連接MySQL數(shù)據(jù)庫(JDBC)詳細(xì)步驟

    這篇文章主要介紹了使用IDEA配置Tomcat和連接MySQL數(shù)據(jù)庫(JDBC)詳細(xì)步驟,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Java將json對(duì)象轉(zhuǎn)換為map鍵值對(duì)案例詳解

    Java將json對(duì)象轉(zhuǎn)換為map鍵值對(duì)案例詳解

    這篇文章主要介紹了Java將json對(duì)象轉(zhuǎn)換為map鍵值對(duì)案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • java使用swing繪制國際象棋棋盤

    java使用swing繪制國際象棋棋盤

    這篇文章主要為大家詳細(xì)介紹了java使用swing繪制國際象棋棋盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • MyBatis3源碼解析之如何獲取數(shù)據(jù)源詳解

    MyBatis3源碼解析之如何獲取數(shù)據(jù)源詳解

    用myBatis3與spring整合的時(shí)候,我們可以通過多種方式獲取數(shù)據(jù)源,下面這篇文章主要給大家介紹了關(guān)于MyBatis3源碼解析之如何獲取數(shù)據(jù)源的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • springboot 如何修改默認(rèn)端口及application.properties常用配置

    springboot 如何修改默認(rèn)端口及application.properties常用配置

    這篇文章主要介紹了springboot 如何修改默認(rèn)端口及application.properties常用配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java正則表達(dá)式——group方法的使用

    Java正則表達(dá)式——group方法的使用

    這篇文章主要介紹了Java正則表達(dá)式group方法的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 使用SpringBoot編寫一個(gè)優(yōu)雅的單元測(cè)試

    使用SpringBoot編寫一個(gè)優(yōu)雅的單元測(cè)試

    這篇文章主要為大家詳細(xì)介紹了如何使用SpringBoot編寫一個(gè)優(yōu)雅的單元測(cè)試,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-07-07
  • Java list與set中contains()方法效率案例詳解

    Java list與set中contains()方法效率案例詳解

    這篇文章主要介紹了Java list與set中contains()方法效率案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08

最新評(píng)論