java多線程

線程六種狀態(tài)

  1. New:尚未啟動(dòng)的線程的線程狀態(tài)(new Thread)
  2. Runnable:可運(yùn)行線程的線程狀態(tài),等待cpu調(diào)度(調(diào)用star)
  3. Blokcked: 線程阻塞等待監(jiān)視器鎖定的線程專狀態(tài),處于synchronized同步代碼塊或方法中被阻塞。
  4. Waiting: 線程等待的線程狀態(tài)。
    不帶timeout參數(shù)的方式調(diào)用Object.wait, thread.jion, LockSupport.park
  5. Timed Waiting: 具有指定等待時(shí)間的等待線程的線程狀態(tài),下列超時(shí)的方式:Thread.sleep, Object.wait, Thread.join, LockSupport.parkNanos, LockSupport.parkUntil
  6. Terminated: 終止線程的線程狀態(tài), 線程正常完成執(zhí)行或者出現(xiàn)異常
public class ScannerTest {
    public static void main(String[] arg) throws InterruptedException {
        test1();
    };
    
    public static void test1() throws InterruptedException{
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("線程1運(yùn)行");
            }
        });
        System.out.println("1調(diào)用前狀態(tài)"+ thread1.getState().toString());
        Thread.sleep(1000L);
        thread1.start();
        System.out.println("2調(diào)用后狀態(tài)"+ thread1.getState().toString());
        Thread.sleep(2000L);
        System.out.println("2s后的狀態(tài)" + thread1.getState().toString());
    }
}

/**
1調(diào)用前狀態(tài)NEW
2調(diào)用后狀態(tài)RUNNABLE
線程1運(yùn)行
2s后的狀態(tài)TERMINATED
**/
public static void test2() throws InterruptedException {
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000L);
                    System.out.println("線程2運(yùn)行" + Thread.currentThread().getState());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        thread2.start();
        System.out.println("調(diào)用后狀態(tài):" + thread2.getState().toString());
        Thread.sleep(2000L);
        System.out.println("等待2s后狀態(tài):" + thread2.getState().toString());
    }
/*
調(diào)用后狀態(tài):RUNNABLE
等待2s后狀態(tài):TIMED_WAITING
線程2運(yùn)行RUNNABLE
*/

public static void test3() throws InterruptedException {
        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("搶鎖之前狀態(tài)" + Thread.currentThread().getState());
                synchronized (ThreadTest.class) {
                    System.out.println("拿到鎖繼續(xù)執(zhí)行" + Thread.currentThread().getState());
                }
            }

        });
        synchronized(ThreadTest.class) {
            thread3.start();
            Thread.sleep(2000L);
            System.out.println("調(diào)用等待2s狀態(tài)" + thread3.getState().toString());
            Thread.sleep(4000L);
            
        }
    }
/*
搶鎖之前狀態(tài)RUNNABLE
調(diào)用等待2s狀態(tài)BLOCKED
拿到鎖繼續(xù)執(zhí)行RUNNABLE

*/

終止線程

1.過(guò)時(shí)的stop方法
如果線程里面的程序沒有執(zhí)行完,會(huì)被終止點(diǎn),后面的不在繼續(xù)執(zhí)行

public class StopThread {
    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        thread.start();
        Thread.sleep(1000);
        thread.stop();
        while(thread.isAlive()) {} // 確保線程被終止了,
        //打印結(jié)果
        thread.print();
    }
}

class MyThread extends Thread{
    private int i=0,j=0;
    @Override
    public void run(){
        synchronized(this) {
            ++i;
            try {
                Thread.sleep(5000);
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
            ++j;
        }
        System.out.println("釋放");
    }
    public void print() {
        System.out.println("i=" + i + "j="+j);
    }
}

// i=1j=0

2.interrupt終止
把上面代碼的thread.stop(); 換成 thread.interrupt();
會(huì)報(bào)錯(cuò), 可以看到雖然終止了程序但是后面依然執(zhí)行了,可以再異常里面做其他處理

java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
釋放
    at com.Hello.ScannerTest.MyThread.run(StopThread.java:23)
i=1j=1
  1. 用標(biāo)志位的方式中斷線程
    在線程外面用一個(gè)標(biāo)志來(lái)判斷線程是否可執(zhí)行
public class StopTh {
    public volatile static boolean flag = true;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            try {
                while(flag) {
                    System.out.println("運(yùn)行");
                    Thread.sleep(1000L);
                }
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        Thread.sleep(3000L);
        flag = false;
        System.out.println("運(yùn)行結(jié)束");
    }
}

/*運(yùn)行
運(yùn)行
運(yùn)行
運(yùn)行結(jié)束
*/

線程封閉

多線程訪問(wèn)共享可變數(shù)據(jù)時(shí),涉及到線程間數(shù)據(jù)同步問(wèn)題
并不是所有時(shí)候,都要用到共享數(shù)據(jù),若數(shù)據(jù)都被封閉在各自的線程之中,就不需要同步,這種通過(guò)將數(shù)據(jù)封閉在線程中而避免使用同步的技術(shù)稱為線程封閉

ThreadLocal

使用ThreadLocal 就算一個(gè)線程改變了值,但是對(duì)其他線程獲取這個(gè)值原來(lái)的數(shù)據(jù) 沒有任何影響

public class ThreadLocalTest {
    public static ThreadLocal<String> value = new ThreadLocal<>();
    
    public static void main(String[] arg0) {
        new Thread(new Runnable() {
            @Override
            public void run () {
                value.set("11111");
                try {
                    Thread.sleep(1000L);
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(value.get());
            }
        }).start();
        
        new Thread(new Runnable() {
            @Override
            public void run () {
                try {
                    Thread.sleep(1000L);
                    System.out.println(value.get());
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

// 11111
// null

棧封閉

局部變量的固有屬性之一就是封閉在線程中
他們位于線程的棧中,其他線程無(wú)法訪問(wèn)這個(gè)棧

線程池

線程池管理器:用于創(chuàng)建并管理線程池,包括創(chuàng)建線程池,銷毀線程池,添加新任務(wù),
工作線程:線程池中線程,可以虛幻的執(zhí)行任務(wù),在沒有任務(wù)時(shí)處于等待狀態(tài);
任務(wù)接口:每個(gè)任務(wù)必須實(shí)現(xiàn)的接口,以供工作線程調(diào)度任務(wù)的執(zhí)行,他主要規(guī)定了任務(wù)的入口,任務(wù)完成后的收尾工作,任務(wù)的執(zhí)行狀態(tài)等;
任務(wù)隊(duì)列:用于存放沒有處理的任務(wù),提供一種緩沖機(jī)制;

線程池類的結(jié)構(gòu):
接口:Executor 最上層的接口,之定義了execute
接口:ExecutorService 繼承了Exexutor ,拓展了Callable,Future,關(guān)閉方法;
接口:ScheduledExecutorService 繼承ExecutorService,增加了定時(shí)任務(wù)相關(guān)的方法,
實(shí)現(xiàn)類:ThreadPoolExecutor 基礎(chǔ),標(biāo)準(zhǔn)的線程池實(shí)現(xiàn)
實(shí)現(xiàn)類: ScheduledThreadPoolExecutor 繼承了ThreadPoolExecutor,實(shí)現(xiàn)了ScheduledExecutorService中相關(guān)定時(shí)任務(wù)的方法

Runnale 和Callable 一些區(qū)別

public class RunnableTest {
    static ThreadPoolExecutor pool = 
            new ThreadPoolExecutor(1, 2, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    public static void main(String args[])throws ExecutionException,InterruptedException {
        Future run_future = pool.submit(new MyRunnable());
        System.err.println("run_future:" + run_future.get());
        Future call_futter =pool.submit(new MyCallable());
        System.err.println("call_future:" + call_futter.get());
    }
}

class MyCallable implements Callable<Integer>{
    @Override
    public Integer call()throws Exception{
        return 1;
    }
}
class MyRunnable implements Runnable{
    @Override
    public void run() {
        return;
    }
}
/*
run_future:null
call_future:1

*/

ThreadPoolExecutor

public class threadPool {
public static void main(String[] arg) throws Exception {
test();
}
private static void test() throws Exception{
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
5, //核心線程數(shù),超時(shí)不會(huì)被清空
10, // 最大線程數(shù)10
5, // 保持的時(shí)間,超時(shí) 沒執(zhí)行的任務(wù)被清空
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(5), // 等待隊(duì)列容量為5
// 最多容納15個(gè)任務(wù),查出的會(huì)被拒絕執(zhí)行
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("有任務(wù)被拒絕執(zhí)行了");

            }
        }
    );
    testCommon(threadPool);
}
public static void testCommon(ThreadPoolExecutor threadPool) throws Exception{
    for(int i=0;i<30; i++) {
        int n = i;
        threadPool.submit(new Runnable() {
            @Override
            public void run () {
                try {
                    System.out.println("任務(wù)"+ n +"開始執(zhí)行");
                    Thread.sleep(3000L);
                    System.out.println("任務(wù)"+ n +"執(zhí)行完成");
                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("任務(wù)" + i + "提交");
    }
    while(true) {
        Thread.sleep(1000);
        System.out.println("》》》線程數(shù)量"+threadPool.getPoolSize());
        System.out.println(">>>任務(wù)隊(duì)列" + threadPool.getQueue().size());
    }
}

}

/*

任務(wù)0提交
任務(wù)0開始執(zhí)行
任務(wù)1提交
任務(wù)2提交
任務(wù)1開始執(zhí)行
任務(wù)3提交
任務(wù)2開始執(zhí)行
任務(wù)4提交
任務(wù)5提交
任務(wù)6提交
任務(wù)7提交
任務(wù)3開始執(zhí)行
任務(wù)4開始執(zhí)行
任務(wù)8提交
任務(wù)9提交
任務(wù)10提交
任務(wù)11提交
任務(wù)12提交
任務(wù)10開始執(zhí)行
任務(wù)13提交
任務(wù)11開始執(zhí)行
任務(wù)12開始執(zhí)行
任務(wù)14提交
有任務(wù)被拒絕執(zhí)行了
任務(wù)15提交
任務(wù)13開始執(zhí)行
任務(wù)16提交
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
任務(wù)17提交
任務(wù)14開始執(zhí)行
任務(wù)18提交
任務(wù)19提交
任務(wù)20提交
任務(wù)21提交
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
任務(wù)22提交
任務(wù)23提交
任務(wù)24提交
任務(wù)25提交
任務(wù)26提交
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
有任務(wù)被拒絕執(zhí)行了
任務(wù)27提交
有任務(wù)被拒絕執(zhí)行了
任務(wù)28提交
有任務(wù)被拒絕執(zhí)行了
任務(wù)29提交
》》》線程數(shù)量10
>>>任務(wù)隊(duì)列5
》》》線程數(shù)量10
>>>任務(wù)隊(duì)列5
任務(wù)1執(zhí)行完成
任務(wù)0執(zhí)行完成
任務(wù)2執(zhí)行完成
任務(wù)7開始執(zhí)行
任務(wù)3執(zhí)行完成
任務(wù)5開始執(zhí)行
任務(wù)6開始執(zhí)行
任務(wù)8開始執(zhí)行
任務(wù)13執(zhí)行完成
任務(wù)4執(zhí)行完成
任務(wù)14執(zhí)行完成
任務(wù)9開始執(zhí)行
任務(wù)12執(zhí)行完成
任務(wù)10執(zhí)行完成
任務(wù)11執(zhí)行完成
》》》線程數(shù)量10
>>>任務(wù)隊(duì)列0
》》》線程數(shù)量10
>>>任務(wù)隊(duì)列0
》》》線程數(shù)量10
>>>任務(wù)隊(duì)列0
任務(wù)7執(zhí)行完成
任務(wù)5執(zhí)行完成
任務(wù)8執(zhí)行完成
任務(wù)6執(zhí)行完成
任務(wù)9執(zhí)行完成
》》》線程數(shù)量10
>>>任務(wù)隊(duì)列0
*/

SynchronousQueue

SynchronousQueue不是一個(gè)真正的隊(duì)列,因?yàn)樗粫?huì)為隊(duì)列中元素維護(hù)存儲(chǔ)空間。 它維護(hù)一組線程,這些線程在等待著把元素加入或移出隊(duì)列。put() 往queue放進(jìn)去一個(gè)element以后就一直wait直到有其他thread進(jìn)來(lái)把這個(gè)element取走。take() 取出并且remove掉queue里的element(認(rèn)為是在queue里的。。。),取不到東西他會(huì)一直等。

public static void test3() throws InterruptedException{
        SynchronousQueue<String> queue = new SynchronousQueue<String>();
        new Thread(new Runnable() {
            @Override
            public void run () {
                try {
                    System.out.println("加入之前");
                    queue.put("新數(shù)據(jù)1");
                    System.out.println("加入之后");
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        Thread.currentThread().sleep(100L);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    Thread.sleep(3000);
                    System.out.println("取出數(shù)據(jù)之前");
                    String takedValue = queue.take();
                    System.out.println("取出來(lái)的數(shù)據(jù): "+takedValue);
                    System.out.println("取出數(shù)據(jù)之后");
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
/*
加入之前
取出數(shù)據(jù)之前
取出來(lái)的數(shù)據(jù): 新數(shù)據(jù)1
取出數(shù)據(jù)之后
加入之后

*/

Executors工具類

newFixedThreadPool(int nThreads)創(chuàng)建一個(gè)固定大小,任務(wù)隊(duì)列容量無(wú)界的線程池,核心線程數(shù)=最大線程數(shù)
newCachedThreadPool 創(chuàng)建的是一個(gè)大小無(wú)界的緩沖線程池,他的任務(wù)隊(duì)列是一個(gè)同步隊(duì)列,任務(wù)加入到池中,如果池中有空閑線程,則用空閑線程執(zhí)行,如果無(wú) 則創(chuàng)建新線程執(zhí)行,池中的線程空襲七年超過(guò)60s將被銷毀釋放,線程數(shù)隨任務(wù)的多少而變化,適用于執(zhí)行耗時(shí)較小的異步任務(wù),池的核心線程數(shù)為0,最大線程數(shù)=Integet.MAX_VALUE
newSingleThreadExecutor() 只有一個(gè)線程來(lái)執(zhí)行無(wú)邊界任務(wù)隊(duì)列的單一線程池,該線程池確保任務(wù)按加入的順序一個(gè)一個(gè)的依次執(zhí)行,當(dāng)唯一的線程因任務(wù)異常終止時(shí),將創(chuàng)建一個(gè)新的線程來(lái)繼續(xù)執(zhí)行后續(xù)的任務(wù),與newFixedThreadPool的區(qū)別在于,單一線程池的池大小在newSingleThreadExecutor方法中編碼,不能在改變的
newScheduledThreadPool(int corePoolSize) 能定時(shí)執(zhí)行任務(wù)的的線程池,該池的核心線程數(shù)由參數(shù)指定,最大線程為Integer.MAX_VALUE

如果確定合適數(shù)量的線程

計(jì)算型任務(wù):cpu數(shù)量的1-2倍
IO型任務(wù):相對(duì)比計(jì)算型任務(wù),需多一些線程,要根據(jù)具體的IO阻塞時(shí)長(zhǎng)進(jìn)行考量決定,也可以考慮根據(jù)需要在一個(gè)最小數(shù)量和最大數(shù)量間自動(dòng)增減線程數(shù)
如tomcat中默認(rèn)的最大線程數(shù)為200

線程消息通知

suspend和resume,

suspend掛起目標(biāo)線程,通過(guò)resume可以恢復(fù)線程執(zhí)行
已被棄用,主要是容易寫出鎖死的代碼
正常使用:

public class Demo {
    public static String ice = null;
    public static void main(String[] arg) throws Exception {
        Demo demo = new Demo();
        demo.test1();
    }
    public void test1() throws Exception{
        Thread thread = new Thread(()->{
            if(ice==null) {
                System.out.println("沒有數(shù)據(jù):"+ice);
                Thread.currentThread().suspend(); // 掛起線程
            }
            System.out.println("有數(shù)據(jù):"+ice);
        });
        thread.start();
        Thread.sleep(1000);
        ice = "1";
        thread.resume(); // 通知有數(shù)據(jù)了
        System.out.println("發(fā)送通知");
    }
}
/*
沒有數(shù)據(jù):null
發(fā)送通知
有數(shù)據(jù):1

*/

異常使用:
suspend和resume會(huì)出現(xiàn)一種問(wèn)題,當(dāng)線程自己拿了鎖,并掛起來(lái)了,其他線程再去拿鎖的話去通知前一個(gè)線程會(huì)出現(xiàn)搶不到鎖的情況

public class Demo {
    public static String ice = null;
    public static void main(String[] arg) throws Exception {
        Demo demo = new Demo();
        demo.test1();
    }
    public void test1() throws Exception{
        Thread thread = new Thread(new Runnable(){
            @Override
            public void run() {
                if(ice==null) {
                    System.out.println("沒有數(shù)據(jù):"+ice);
                    synchronized(Demo.class) {
                        Thread.currentThread().suspend();
                    }
                }
                System.out.println("有數(shù)據(jù):"+ice);
            }
        });
        thread.start();
        Thread.sleep(1000L);
        ice = "1";
        synchronized(Demo.class) {
                        System.out.println("發(fā)送通知");
            thread.resume(); // 通知有數(shù)據(jù)了
        }
    }
}

/*
沒有數(shù)據(jù):null

*/

還有一種情況是線程里面在6s中的時(shí)候執(zhí)行suspend,但是在3s的時(shí)候其他線程就已經(jīng)調(diào)用resume通知了的話,掛起的線程也是接收不到消息的

wait/notify機(jī)制

wait 方法導(dǎo)致當(dāng)前線程等待,加入該對(duì)象的等待集合中,并且放棄當(dāng)前持有的對(duì)象鎖,
notify/notifyAll方法喚醒一個(gè)或所有正在等待這個(gè)對(duì)象鎖的線程
注意1:雖然會(huì)wait自動(dòng)解鎖,但是對(duì)順序有要求,如果notify被調(diào)用之后,才開始wait方法的調(diào)用,線程會(huì)永遠(yuǎn)處于waiting狀態(tài)
注意2:這些方法只能由同一對(duì)象鎖的持有者線程調(diào)用,也就是卸載同步快里面,否則會(huì)拋出lllegalMStateException異常

wait/notify只能在synchronized關(guān)鍵字中使用

public void test2() {
        try {
            wait();
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
/*
Exception in thread "main" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at com.Hello.ScannerTest.Demo.test2(Demo.java:11)
    at com.Hello.ScannerTest.Demo.main(Demo.java:7)

*/

public void test2() {
        try {
            synchronized(this) {
                wait();
            }
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
// 無(wú)異常

正常用法

public void test3() throws Exception {
        new Thread(()->{
            if(ice==null) {
                synchronized(this){
                    try {
                        System.out.println("沒用數(shù)據(jù):"+ice);
                        this.wait();
                        System.out.println("拿到數(shù)據(jù):"+ice);
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                
            }
        }).start();
        Thread.sleep(1000L);
        ice = "1";
        synchronized(this) {
            System.out.println("拿到鎖,通知");
            this.notifyAll();
        }
    }
/*
沒用數(shù)據(jù):null
拿到鎖,通知
拿到數(shù)據(jù):1

*/

注意:此處使用的是lambda表達(dá)式,里面的this會(huì)指向父級(jí),所以這里兩個(gè)synchronized里面的this都是在同一個(gè)作用域下的,所以這里的this會(huì)通知到,沒問(wèn)題,也就是上面所說(shuō)的需要注意的第二點(diǎn),方法只能在同一個(gè)線程線程鎖的對(duì)象里面調(diào)用
錯(cuò)誤示范:

public void test3() throws Exception {
        new Thread(new Runnable(){
            @Override
            public void run () {
                if(ice==null) {
                    synchronized(this){
                        try {
                            System.out.println("沒用數(shù)據(jù):"+ice);
                            this.wait();
                            System.out.println("拿到數(shù)據(jù):"+ice);
                        }catch(InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    
                }
            }
        }).start();
        Thread.sleep(1000L);
        ice = "1";
        synchronized(this) {
            System.out.println("拿到鎖,通知");
            this.notifyAll();
        }
    }

/*
沒用數(shù)據(jù):null
拿到鎖,通知

*/

需要改成這樣

public class Demo {
    public static String ice = null;
    public static void main(String[] arg) throws Exception {
        Demo demo = new Demo();
        demo.test3();
    }
    public void test3() throws Exception {
        new Thread(new Runnable(){
            @Override
            public void run () {
                if(ice==null) {
                    synchronized(Demo.class){
                        try {
                            System.out.println("沒用數(shù)據(jù):"+ice);
                            Demo.class.wait();
                            System.out.println("拿到數(shù)據(jù):"+ice);
                        }catch(InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    
                }
            }
        }).start();
        Thread.sleep(1000L);
        ice = "1";
        synchronized(Demo.class) {
            System.out.println("拿到鎖,通知");
            Demo.class.notifyAll();
        }
    }
}
/*
沒用數(shù)據(jù):null
拿到鎖,通知
拿到數(shù)據(jù):1
*/

park/ unpark機(jī)制

線程調(diào)用park則等待“許可”, unpark為線程提供許可
調(diào)用unpark之后再調(diào)用park線程會(huì)直接運(yùn)行
提前調(diào)用的unpark不疊加,連續(xù)多次調(diào)用unpark之后,第一次調(diào)用park后會(huì)拿到“許可”,直接運(yùn)行,后續(xù)調(diào)用會(huì)進(jìn)入等待

package com.Hello.ScannerTest;

import java.util.concurrent.locks.LockSupport;

public class ParkUnparkDemo {
    public static void main(String args[]) throws Exception {
        ParkUnparkDemo demo = new ParkUnparkDemo();
        demo.test1();
    }
    public static Object ice = null;
    
    public void test1() throws Exception{
        
        Thread consume = new Thread(() -> {
            if(ice == null) {
                System.out.println("準(zhǔn)備掛起");
                LockSupport.park();
            }
            System.out.println("完成---");
        });
        consume.start();
        Thread.sleep(3000);
        ice = new Object();
        
        LockSupport.unpark(consume);
        System.out.println("解鎖--");
    }
}
/*
準(zhǔn)備掛起
解鎖--
完成---
*/

注意: 上面的代碼用的if語(yǔ)句來(lái)判斷,時(shí)候進(jìn)入等待狀態(tài),這樣的做法有問(wèn)題,官方建議應(yīng)該在循環(huán)中檢查等待條件, 因?yàn)樘幱诘却隣顟B(tài)的線程可能會(huì)收到錯(cuò)誤警報(bào)和喚醒,如果不在循環(huán)中檢測(cè)等待條件,程序會(huì)在沒有滿足條件下推出,
為喚醒: 是指線程并非因?yàn)閚otify, notifyall, unpark等api調(diào)用而意外喚醒,是更底層原因?qū)е碌?br> 如上面代碼

Thread consume = new Thread(() -> {
            if(ice == null) { 
                System.out.println("準(zhǔn)備掛起");
                LockSupport.park();
            }
            System.out.println("完成---");
        });
/*
如果ice不滿足條件, Locksupport.park()突然被喚醒,那么就會(huì)執(zhí)行下面的 “完成---”, 
*/
while(ice == null) { 
                System.out.println("準(zhǔn)備掛起");
                LockSupport.park();
            }
當(dāng)if改成while后,即使被喚醒了,還是不滿足條件,程序繼續(xù)被掛起,等待著
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 線程池ThreadPoolExecutor corepoolsize:核心池的大小,默認(rèn)情況下,在創(chuàng)建了線程池之后...
    irckwk1閱讀 875評(píng)論 0 0
  • Java 多線程 多線程:指的是這個(gè)程序(一個(gè)進(jìn)程)運(yùn)行時(shí)產(chǎn)生了不止一個(gè)線程 并行與并發(fā):并行:多個(gè)cpu實(shí)例或者...
    LarryLeo_9605閱讀 335評(píng)論 0 3
  • Java 多線程 多線程:指的是這個(gè)程序(一個(gè)進(jìn)程)運(yùn)行時(shí)產(chǎn)生了不止一個(gè)線程 并行與并發(fā): 并行:多個(gè)cpu實(shí)例或...
    編程小世界閱讀 151評(píng)論 0 0
  • 0. 前言 Java 為了實(shí)現(xiàn)跨平臺(tái),在語(yǔ)言層面上實(shí)現(xiàn)了多線程。我們只需要熟悉 Java 這一套多線程機(jī)制就行了,...
    WolfXu閱讀 1,461評(píng)論 0 6
  • Java 多線程 線程和進(jìn)程的區(qū)別 線程和進(jìn)程的本質(zhì):由CPU進(jìn)行調(diào)度的并發(fā)式執(zhí)行任務(wù),多個(gè)任務(wù)被快速輪換執(zhí)行,使...
    安安zoe閱讀 2,268評(píng)論 1 18

友情鏈接更多精彩內(nèi)容