基礎(chǔ)4-高級(jí)-多線程

概念 實(shí)現(xiàn)方式 線程方法 線程同步 線程安全 線程死鎖 線程通訊 線程互斥鎖

概念

多線程:如果把QQ比作進(jìn)程,那么既聊天,又玩農(nóng)場(chǎng),就是多線程
并發(fā):甲任務(wù)與乙任務(wù)切換進(jìn)行
并行:甲任務(wù)與乙任務(wù)同時(shí)進(jìn)行
舉例:jvm是多線程,Jvm啟動(dòng)了垃圾回收線程和主線程

實(shí)現(xiàn)方式:三種

第一種---Thread類

public class  HelloWorld {
    public static void main(String[] args) {
        //3、啟動(dòng)start
       new thread().start();
        for (int i=0;i<100000;i++){
            System.out.println("主線程");
        }
    }
}
//1、繼承Thread
class thread extends Thread{
    //2、實(shí)現(xiàn)run方法
   public void run(){
       for (int i=0;i<100000;i++){
           System.out.println("副線程");
       }
   }
}



第二種---Runnable接口

public class  HelloWorld {
    public static void main(String[] args) {
        //3、調(diào)用Thread類
        Thread th = new Thread(new thread());
        //4、啟動(dòng)start方法
        th.start();
        for (int i=0;i<100000;i++){
            System.out.println("主線程");
        }
    }
}
//1、實(shí)現(xiàn)Runnable
class thread implements Runnable{
    //2、實(shí)現(xiàn)run方法
   public void run(){
       for (int i=0;i<100000;i++){
           System.out.println("副線程");
       }
   }
}


第三種---匿名方式

public class  HelloWorld {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<100000;i++){
                    System.out.println("第一線程");
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<100000;i++){
                    System.out.println("第二線程");
                }
            }
        }).start();
    }
}

線程方法

1、優(yōu)先級(jí) setPriority()
2、睡眠時(shí)間 sleep()
3、線程插隊(duì) join()
4、禮讓線程 yield()
5、后臺(tái)運(yùn)行 setDaemon(true)


public class  HelloWorld {
    public static void main(String[] args) {
        Thread th=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<100000;i++){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("第一線程");
                }
            }
        });

        Thread th2=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<100000;i++){
                    if (i == 9999){
                        try {
                            th.join();//線程插隊(duì)
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if (i == 54654){
                        Thread.yield();//讓出CPU
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("第二線程");
                }
            }
        });
        th.setPriority(8);//從1-10 逐次增加
        th.setDaemon(true);//設(shè)置守護(hù)線程(后臺(tái)運(yùn)行,占資源少)
        th.start();
        th2.start();
    }
}

線程同步

package exercise;
/*
當(dāng)多線程并發(fā), 有多段代碼同時(shí)執(zhí)行時(shí), 我們希望某一段代碼執(zhí)行的過程中
CPU不要切換到其他線程工作,這時(shí)就需要同步。如果兩段代碼是同步的,
那么同一時(shí)間只能執(zhí)行一段, 在一段代碼沒執(zhí)行結(jié)束之前, 不會(huì)執(zhí)行另外一段
代碼。所謂同步代碼塊就是使用synchronized關(guān)鍵字加上一個(gè)鎖對(duì)象來定義
一段代碼,這就叫同步代碼塊,多個(gè)同步代碼塊如果使用相同的鎖對(duì)象,那
么他們就是同步的。
 * */
class exercise{
    //開始跑類方法
    public static void main(String[] args) {
        Print print=new Print();
        new Thread(){
            public void run(){
                while(true){
                    print.print();
                }
            }
        }.start();
        
        new Thread(){
            public void run(){
                while(true){
                    print.print1();
                }
            }
        }.start();
    }
}
//創(chuàng)建對(duì)象,創(chuàng)建方法
class Print {
    Demo demo=new Demo();
    public void print(){
        synchronized (demo) {
            System.out.println("黑馬");
            System.out.println("程序");
        }
    }
    public void print1(){
        synchronized(demo){
            System.out.println("傳智");
            System.out.println("博客");
        }
    }
}
//要跑的類
class Demo{}

線程安全


多線程安全問題:兩個(gè)線程在同時(shí)刻,只能其中一個(gè)參與運(yùn)算,另外一個(gè)必須等待。
通俗理解:兩個(gè)同學(xué)在餐廳同時(shí)搶第一個(gè)位置,結(jié)果自己想吧!
解決方法:給線程上鎖,在這個(gè)線程上鎖期間,不能有其他線程介入運(yùn)行,這樣就解決問題了!


public class  HelloWorld {
    public static void main(String[] args) {
        new Ticket().start();
        new Ticket().start();
        new Ticket().start();
        new Ticket().start();
    }
}
class Ticket extends Thread{
    private static int ticket = 100;
    public void run(){
        while (true){
            //上鎖
            synchronized (Ticket.class){
                if(ticket<=0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    break;
                }
                System.out.println(getName()+"第"+ ticket-- +"張票售出");
            }
        }
    }
}

線程死鎖

/*一個(gè)線程持有鎖,沒釋放這個(gè)鎖之前,其他線程獲取不到此鎖,
如果其他線程非要此鎖,就要死等,這種情況,就是死鎖。
*/

線程通訊

等待:wait
單個(gè)喚醒:notify
全部喚醒:notifyAll



public class  HelloWorld {
    public static void main(String[] args) {
        Ticket t = new Ticket();
        new Thread(){
            public void run(){
                while (true){
                    try {
                        t.print1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread(){
            public void run(){
                while (true){
                    try {
                        t.print2();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread(){
            public void run(){
                while (true){
                    try {
                        t.print3();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}
class Ticket {
    private int ticket = 1;
    public void print1() throws InterruptedException {
        synchronized (this){
            if (ticket != 1){
                this.wait();//睡眠
            }
            System.out.println("線程一");
            ticket=2;
            this.notify();//喚醒
        }
    }

    public void print2() throws InterruptedException {
        synchronized (this){
            if (ticket != 2){
                this.wait();//睡眠
            }
            System.out.println("線程二");
            ticket=3;
            this.notify();//喚醒
        }
    }

    public void print3() throws InterruptedException {
        synchronized (this){
            if (ticket != 3){
                this.wait();//睡眠
            }
            System.out.println("線程三");
            ticket=1;
            this.notify();//喚醒
        }
    }
}

線程互斥鎖

ReentrantLock 
Condition
/*
 * 互斥鎖是JDK1.5版本的新特性,包含了多線程通訊、多線程鎖,比起之前的更具有靈活性。
 * 
 * */

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class  HelloWorld {
    public static void main(String[] args) {
        Ticket t = new Ticket();
        new Thread(){
            public void run(){
                while (true){
                    try {
                        t.print1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread(){
            public void run(){
                while (true){
                    try {
                        t.print2();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread(){
            public void run(){
                while (true){
                    try {
                        t.print3();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}
class Ticket {
    private ReentrantLock r = new ReentrantLock();//互斥鎖
    private Condition c1 = r.newCondition();//通訊1
    private Condition c2 = r.newCondition();//通訊2
    private Condition c3 = r.newCondition();//通訊3
    private int ticket = 1;
    public void print1() throws InterruptedException {
        r.lock();//啟動(dòng)鎖
            if (ticket != 1){
                c1.await();//等待
            }
            System.out.println("線程一");
            ticket=2;
            c1.signal();//喚醒
        r.unlock();//關(guān)閉鎖
    }

    public void print2() throws InterruptedException {
        r.lock();//啟動(dòng)鎖
            if (ticket != 2){
                c2.await();//睡眠
            }
            System.out.println("線程二");
            ticket=3;
            c2.signal();//喚醒
        r.unlock();//關(guān)閉鎖
    }

    public void print3() throws InterruptedException {
        r.lock();//啟動(dòng)鎖
            if (ticket != 3){
                c3.await();//睡眠
            }
            System.out.println("線程三");
            ticket=1;
            c3.signal();//喚醒
        r.unlock();//關(guān)閉鎖
    }
}

線程組

//線程組:安全第一,A在1線程組內(nèi),A就不能修改2線程組數(shù)據(jù)。
//線程池:效率第一,A線程干完活,不結(jié)束他,讓他睡眠,需要再喚醒。
package exercise;
public class exercise {
    public static void main(String[] args) {
        ThreadGroup tg = new ThreadGroup("我是一個(gè)新線程");//創(chuàng)建線程組
        MyRunnable mr = new MyRunnable();//創(chuàng)建Runnable的子類對(duì)象
        Thread t1= new Thread(tg,mr,"張三");//將線程t1放在組中
        Thread t2= new Thread(tg,mr,"李四");//將線程t2放在組中
        System.out.println(t1.getThreadGroup().getName());//獲取組名
        System.out.println(t2.getThreadGroup().getName());
    }
}
class MyRunnable implements Runnable{
    public void run() {
        for(int i=0;i<100;i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }
}

線程池

//一般我們創(chuàng)建少量線程,并不會(huì)出現(xiàn)太大問題,可是實(shí)際開發(fā)中我們
//可能要用到n多線程,頻繁創(chuàng)建和銷毀線程會(huì)嚴(yán)重銷毀系統(tǒng)資源,
//針對(duì)這一問題,出現(xiàn)了線程池技術(shù),線程池可以對(duì)線程回收再利用
package exercise;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class exercise {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);//第四步,創(chuàng)建線程池對(duì)象
        pool.submit(new MyRunnable());//第五步,將線程放到池子里
        pool.submit(new MyRunnable());
        pool.shutdown();//第六步,關(guān)閉線程池
    }
}
class MyRunnable implements Runnable{//第一步
    public void run() {//第二步
        for(int i=0;i<100;i++) {//第三步
            System.out.println(Thread.currentThread().getName());
        }
    }
}

線程生命周期


123.png

線程定時(shí)器(Timer)

package exercise;
import java.io.IOException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
class exercise {
    @SuppressWarnings("deprecation")
    public static void main(String[] args) throws IOException, InterruptedException {
        Timer t = new Timer();//第四步,創(chuàng)建計(jì)數(shù)器
        t.schedule(new Time(), new Date(118,8,0,20,28,00));//new time();時(shí)間到了顯示起床啦
        //new Data();設(shè)定時(shí)間
        //年是2018-1900年
        //月是9月
        //日是1日
        //時(shí)分秒 21點(diǎn) 23分 00秒
        while(true) {//設(shè)定時(shí)間
            Thread.sleep(1000);
            System.out.println(new Date());
        }
    }
}
class Time extends TimerTask{//第一步
    public void run() {//第二步
        System.out.println("起床啦");//第三步
    }
}

最后編輯于
?著作權(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)容

  • 本文將從以下幾個(gè)部分來介紹多線程。 第一部分介紹多線程的基本原理。 第二部分介紹Run loop。 第三部分介紹多...
    曲年閱讀 1,339評(píng)論 2 14
  • 一、進(jìn)程和線程 進(jìn)程 進(jìn)程就是一個(gè)執(zhí)行中的程序?qū)嵗?,每個(gè)進(jìn)程都有自己獨(dú)立的一塊內(nèi)存空間,一個(gè)進(jìn)程中可以有多個(gè)線程。...
    阿敏其人閱讀 2,699評(píng)論 0 13
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請(qǐng)注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,297評(píng)論 0 14
  • 前幾天下載了這個(gè)軟件,今天才突然想起來要好好看看。(還是在上課的時(shí)候偷偷看的,專業(yè)課太枯燥無聊了)我著重看了一...
    欣然娜拉閱讀 434評(píng)論 4 3
  • 信用卡是因賒賬而出現(xiàn)的。顧客拿著信用卡購物,就是告訴商家我要這東西,但要賒賬。賒賬需要憑證,憑證就是這張卡。這張卡...
    xxwade閱讀 562評(píng)論 1 1

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