Java多線程學(xué)習(xí)筆記
多任務(wù)、多線程
在多任務(wù)場景下,兩件事看上去同時(shí)在做,但實(shí)際上,你的大腦在同一時(shí)間只做一件事,間隔時(shí)間可能很少,但這似乎讓你感覺這兩件事是同時(shí)在做
考慮阻塞問題,引入多線程的場景,多線程并發(fā)場景

程序、進(jìn)程、線程
程序=指令+數(shù)據(jù)(靜態(tài)的)
在操作系統(tǒng)中運(yùn)行的程序就是進(jìn)程,一個(gè)進(jìn)程可以有多個(gè)線程
比如,看視頻時(shí)聽聲音,看圖像,看彈幕等
學(xué)著看jdk文檔
比如你要看Thread
你可以搜索,然后閱讀

往下翻你會(huì)看到:



線程的創(chuàng)建
1.繼承Thread類
//創(chuàng)建線程方式一:繼承Thread類,重寫run方法,調(diào)用start()方法開啟線程
public class TestThread1 extends Thread{
@Override
public void run() {
//run()方法線程體
IntStream.range(0,20).forEach(i->{
System.out.println("我在看代碼"+i);
});
}
public static void main(String[] args) {
//創(chuàng)建一個(gè)線程對(duì)象
TestThread1 testThread1=new TestThread1();
//調(diào)用start()方法,啟動(dòng)線程,不一定立即執(zhí)行,由cpu調(diào)度執(zhí)行
testThread1.start();
//主方法 main方法
IntStream.range(0,20).forEach(i->{
System.out.println("我在學(xué)習(xí)多線程"+i);
});
}
}
一個(gè)小練習(xí):
//練習(xí)thread實(shí)現(xiàn)對(duì)線程同步下載圖片
public class TestThread2 extends Thread{
private String url;
private String name;
public TestThread2(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownload webDownload=new WebDownload();
webDownload.downloader(url,name);
System.out.println("下載了文件名:"+name);
}
public static void main(String[] args) {
TestThread2 t1=new TestThread2("https://profile.csdnimg.cn/B/D/2/3_sxh06","1.jpg");
TestThread2 t2=new TestThread2("https://profile.csdnimg.cn/B/D/2/3_sxh06","2.jpg");
TestThread2 t3=new TestThread2("https://profile.csdnimg.cn/B/D/2/3_sxh06","3.jpg");
t1.start();
t2.start();
t3.start();
}
}
//下載器
class WebDownload{
//下載方法
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO異常,downloader方法出錯(cuò)");
}
}
}
2.實(shí)現(xiàn)Runable接口
//創(chuàng)建線程的方法2:實(shí)現(xiàn)Runable接口
public class TestThread3 implements Runnable{
@Override
public void run() {
//run()方法線程體
IntStream.range(0,20).forEach(i->{
System.out.println("我在看代碼"+i);
});
}
public static void main(String[] args) {
//創(chuàng)建一個(gè)線程對(duì)象
TestThread3 testThread3=new TestThread3();
//調(diào)用start()方法,啟動(dòng)線程,不一定立即執(zhí)行,由cpu調(diào)度執(zhí)行
// Thread thread=new Thread(testThread3);
// thread.start();
//或者這樣簡寫
new Thread(testThread3).start();
//主方法 main方法
IntStream.range(0,100).forEach(i->{
System.out.println("我在學(xué)習(xí)多線程"+i);
});
}
}

理解并發(fā)的場景
當(dāng)多個(gè)線程使用同一個(gè)資源時(shí),會(huì)出現(xiàn)問題,看看下面這個(gè)買火車票的例子:
public class TestThread4 implements Runnable{
//票數(shù)
private int ticketNums=10;
@Override
public void run() {
while(true){
if (ticketNums<=0){
break;
}
//模擬延遲
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"張票");
}
}
public static void main(String[] args) {
TestThread4 ticket=new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"張三").start();
new Thread(ticket,"李四").start();
}
}
看看運(yùn)行的結(jié)果:

可以看到案例中的線程不安全問題,同時(shí)數(shù)據(jù)也是不正確的
龜兔賽跑場景
/**
* 模擬龜兔賽跑
*/
public class Race implements Runnable{
//勝利者
private static String winner;
@Override
public void run() {
for (int i=0;i<=100;i++){
//模擬兔子休息
if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean flag=gameOver(i);
if (flag){ //判斷比賽是否結(jié)束
break;
}
System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
}
}
/**
* 判斷比賽是否結(jié)束
*/
private boolean gameOver(int steps){
//判斷是否有勝利者
if (winner !=null){
//已經(jīng)存在勝利者
return true;
}else if (steps >= 100){
winner=Thread.currentThread().getName();
System.out.println("勝利者是:"+winner);
return true;
}else{
return false;
}
}
public static void main(String[] args) {
Race race=new Race();
new Thread(race,"兔子").start();
new Thread(race,"烏龜").start();
}
}
實(shí)現(xiàn)callable接口
//線程創(chuàng)建方式3
public class TestCallable implements Callable<Boolean> {
private String url;
private String name;
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
com.sxh.thread.WebDownload webDownload=new com.sxh.thread.WebDownload();
webDownload.downloader(url,name);
System.out.println("下載了文件名:"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable t1=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","1.jpg");
TestCallable t2=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","2.jpg");
TestCallable t3=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","3.jpg");
//創(chuàng)建執(zhí)行服務(wù)
ExecutorService ser= Executors.newFixedThreadPool(3);
//提交執(zhí)行
Future<Boolean> r1=ser.submit(t1);
Future<Boolean> r2=ser.submit(t2);
Future<Boolean> r3=ser.submit(t3);
//獲取結(jié)果
boolean rs1=r1.get();
boolean rs2=r2.get();
boolean rs3=r3.get();
//關(guān)閉服務(wù)
ser.shutdownNow();
}
}
理解函數(shù)式接口
任何接口,只包含唯一一個(gè)抽象方法,就是函數(shù)式接口
/**
* lambdab表達(dá)式的發(fā)展
*/
public class TestLambda1 {
//3.靜態(tài)內(nèi)部類
static class Like2 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda2");
}
}
public static void main(String[] args) {
ILike like=new Like();
like.lambda();
like=new Like2();
like.lambda();
//4.局部內(nèi)部類
class Like3 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda3");
}
}
like=new Like3();
like.lambda();
//5.匿名內(nèi)部類
like=new ILike() {
@Override
public void lambda() {
System.out.println("i like lambda4");
}
};
like.lambda();
//6.用lambda簡化
like=()->{
System.out.println("i like lambda5");
};
like.lambda();
}
}
//1.定義一個(gè)函數(shù)式接口
interface ILike{
void lambda();
}
//2.實(shí)現(xiàn)類
class Like implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda");
}
}
理解線程的狀態(tài)

線程停止
public class TestStop implements Runnable{
//1.設(shè)置一個(gè)標(biāo)志位
private boolean flag=true;
@Override
public void run() {
int i=0;
while (flag){
System.out.println("run...thread.."+i++);
}
}
//2.設(shè)置一個(gè)公開的方法停止線程,轉(zhuǎn)換標(biāo)志位
public void stop(){
this.flag=false;
}
public static void main(String[] args) {
TestStop stop=new TestStop();
new Thread(stop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if (i==900){
//調(diào)用stop方法,讓線程停止
stop.stop();
System.out.println("線程該停止了");
}
}
// IntStream.range(0,1000).forEach(i->{
//
// });
}
}
線程休眠sleep
每個(gè)對(duì)象都有一把鎖,sleep不會(huì)釋放鎖
1.網(wǎng)路延遲
//模擬延遲
try {
Thread.sleep(200); //ms
} catch (InterruptedException e) {
e.printStackTrace();
}
2.倒計(jì)時(shí)等
public static void main(String[] args) {
try {
tendown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void tendown() throws InterruptedException {
int num=10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if(num<=0)
{
break;
}
}
}
public static void main(String[] args) {
//打印系統(tǒng)當(dāng)前時(shí)間
Date startTime=new Date(System.currentTimeMillis());
while (true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
startTime=new Date(System.currentTimeMillis());//更新時(shí)間
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
線程禮讓yield
//線程禮讓 禮讓不一定成功,由cpu重新調(diào)度
public class TestYield {
public static void main(String[] args) {
MyYield myYield=new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"線程開始執(zhí)行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"線程停止執(zhí)行");
}
}
線程強(qiáng)制執(zhí)行
//測試join方法 想象為插隊(duì)
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("線程vip來了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
//啟動(dòng)線程
TestJoin testJoin=new TestJoin();
Thread thread=new Thread(testJoin);
thread.start();
//主線程
for (int i = 0; i < 1000; i++) {
if (i==200){
thread.join(); //插隊(duì)
}
System.out.println("main"+i);
}
}
}
觀察線程狀態(tài)
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("http://");
});
//觀察狀態(tài)
Thread.State state=thread.getState();
System.out.println(state); //NEW
//啟動(dòng)后
thread.start();
state=thread.getState();
System.out.println(state); //Run
while (state != Thread.State.TERMINATED)
{
Thread.sleep(100);
state=thread.getState();//更新線程狀態(tài)
System.out.println(state); //Run
}
}
}
線程的優(yōu)先級(jí)
//測試線程的優(yōu)先級(jí)
public class TestPriority {
public static void main(String[] args) {
//主線程默認(rèn)優(yōu)先級(jí)
System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
MyPriority myPriority=new MyPriority();
Thread t1=new Thread(myPriority);
Thread t2=new Thread(myPriority);
Thread t3=new Thread(myPriority);
Thread t4=new Thread(myPriority);
Thread t5=new Thread(myPriority);
Thread t6=new Thread(myPriority);
//先設(shè)置優(yōu)先級(jí),在啟動(dòng)
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
t5.setPriority(-1);
t5.start();
t6.setPriority(11);
t6.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
}
}
守護(hù)線程
線程分為用戶線程和守護(hù)線程
//測試守護(hù)線程
public class TestDaemon {
public static void main(String[] args) {
God god=new God();
You you=new You();
Thread thread=new Thread(god);
thread.setDaemon(true); //默認(rèn)是false表示用戶線程
thread.start();
new Thread(you).start();
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝保佑著你");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36000; i++) {
System.out.println("你活著"+i);
}
System.out.println("goodbye!!");
}
}
線程同步機(jī)制
解決安全性問題:隊(duì)列+鎖
1.synchronized 同步方法
默認(rèn)鎖的是this,如需鎖其他的,使用下面的同步塊
//synchronized 同步方法
private synchronized void buy(){
if (ticketNums<=0){
flag=false;
return;
}
//模擬延遲
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//買票
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"張票");
}
2.同步塊synchronized(Obj){}
鎖的對(duì)象是變化的量,需要增刪改的對(duì)象
obj稱之為同步監(jiān)視器,即監(jiān)視對(duì)象
public class UnsafeList {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
lock
class A{
//ReentrantLock 可重入鎖
private final ReentrantLock lock=new ReentrantLock();
public void f(){
lock.lock();//加鎖
try{
//.....
}
finally{
lock.unlock();//釋放鎖
}
}
}
synchronized與lock
- lock是顯示鎖需要手動(dòng)開關(guān),synchronized是隱式鎖,出了作用域自動(dòng)釋放
- lock只有代碼塊鎖,synchronized有代碼塊鎖和方法鎖
- JVM將花費(fèi)更少的時(shí)間來調(diào)度線程,性能更好,更有擴(kuò)展性
- 優(yōu)先使用:Lock>同步代碼塊>同步方法
到此這篇關(guān)于Java多線程學(xué)習(xí)筆記的文章就介紹到這了,更多相關(guān)Java 多線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MybatisPlusInterceptor依賴變紅如何解決,無法識(shí)別問題
這篇文章主要介紹了MybatisPlusInterceptor依賴變紅如何解決,無法識(shí)別問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
java獲取http請(qǐng)求的Header和Body的簡單方法
下面小編就為大家?guī)硪黄猨ava獲取http請(qǐng)求的Header和Body的簡單方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11
Java中的ReentrantReadWriteLock使用詳解
這篇文章主要介紹了Java中的ReentrantReadWriteLock使用詳解,ReentrantReadWriteLock是Java中的一個(gè)鎖實(shí)現(xiàn),它提供了讀寫分離的功能,這種讀寫分離的機(jī)制可以提高并發(fā)性能,特別適用于讀多寫少的場景,需要的朋友可以參考下2023-11-11
java 實(shí)現(xiàn)多線程的方法總結(jié)
這篇文章主要介紹了java 實(shí)現(xiàn)多線程的方法總結(jié)的相關(guān)資料,需要的朋友可以參考下2016-10-10
Java設(shè)計(jì)模式之原型模式詳細(xì)解讀
這篇文章主要介紹了Java設(shè)計(jì)模式之原型模式詳細(xì)解讀,原型模式屬于創(chuàng)建型設(shè)計(jì)模式,用于創(chuàng)建重復(fù)的對(duì)象,且同時(shí)又保證了性能,該設(shè)計(jì)模式的好處是將對(duì)象的創(chuàng)建與調(diào)用方分離,需要的朋友可以參考下2023-12-12

