溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java多線程的示例分析

發(fā)布時間:2021-07-05 09:37:10 來源:億速云 閱讀:118 作者:小新 欄目:開發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)Java多線程的示例分析的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

線程的創(chuàng)建

1.繼承Thread

2.實現(xiàn)Runnable

3.實現(xiàn)Callable

使用繼承Thread類來開發(fā)多線程的應用程序在設計上是有局限性的,因為Java是單繼承。

繼承Thread類

public class ThreadDemo1 {
    // 繼承Thread類 寫法1
    static class MyThread extends Thread{
        @Override
        public void run() {
            //要實現(xiàn)的業(yè)務代碼
        }
    }
    // 寫法2
    Thread thread = new Thread(){
        @Override
        public void run() {
            //要實現(xiàn)的業(yè)務代碼
        }
    };
}

實現(xiàn)Runnable接口

//實現(xiàn)Runnable接口 寫法1
class MyRunnable implements Runnable{
    @Override
    public void run() {
        //要實現(xiàn)的業(yè)務代碼
    }
}
//實現(xiàn)Runnable接口 寫法2 匿名內(nèi)部類
class MyRunnable2 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                //要實現(xiàn)的業(yè)務代碼
            }
        });
    }
}

實現(xiàn)Callable接口(Callable + FutureTask 創(chuàng)建帶有返回值的線程)

package ThreadDeom;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
 * user:ypc;
 * date:2021-06-11;
 * time: 17:34;
 */
//創(chuàng)建有返回值的線程 Callable + Future
public class ThreadDemo2 {
    static class MyCallable implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            return 0;
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //創(chuàng)建Callable子對象
        MyCallable myCallable = new MyCallable();
        //使用FutureTask 接受 Callable
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        //創(chuàng)建線程并設置任務
        Thread thread = new Thread(futureTask);
        //啟動線程
        thread.start();
        //得到線程的執(zhí)行結(jié)果
        int num = futureTask.get();
    }
}

也可以使用lambda表達式

class ThreadDemo21{
    //lambda表達式
    Thread thread = new Thread(()-> {
        //要實現(xiàn)的業(yè)務代碼
    });
}

Thread的構(gòu)造方法

Java多線程的示例分析

線程常用方法

獲取當前線程的引用、線程的休眠

class Main{
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(1000);
        //休眠1000毫秒之后打印
        System.out.println(Thread.currentThread());
        System.out.println(Thread.currentThread().getName());
    }
}

Java多線程的示例分析

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-11;
 * time: 18:38;
 */
public class ThreadDemo6 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("線程的ID:" + Thread.currentThread().getId());
                System.out.println("線程的名稱:" + Thread.currentThread().getName());
                System.out.println("線程的狀態(tài):" + Thread.currentThread().getState());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"線程一");
        thread.start();
        Thread.sleep(100);
        //打印線程的狀態(tài)
        System.out.println("線程的狀態(tài):"+thread.getState());
        System.out.println("線程的優(yōu)先級:"+thread.getPriority());
        System.out.println("線程是否存活:"+thread.isAlive());
        System.out.println("線程是否是守護線程:"+thread.isDaemon());
        System.out.println("線程是否被打斷:"+thread.isInterrupted());
    }
}

Java多線程的示例分析

線程的等待

假設有一個坑位,thread1 和 thread2 都要上廁所。一次只能一個人上,thread2只能等待thread1使用完才能使用廁所。就可以使用join()方法,等待線程1執(zhí)行完,thread2在去執(zhí)行。?

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 10:48;
 */
public class ThreadDemo13 {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"?");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"出來了");
            }
        };
        Thread t1 = new Thread(runnable,"thread1");
        t1.start();
        //t1.join();
        Thread t2 = new Thread(runnable,"thread2");
        t2.start();
    }
}

Java多線程的示例分析

沒有join()顯然是不行的。加上join()之后:

Java多線程的示例分析

線程的終止

1.自定義實現(xiàn)線程的終止
package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 9:59;
 */
public class ThreadDemo11 {
    private static boolean flag = false;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!flag){
                    System.out.println("我是 : " + Thread.currentThread().getName() + ",我還沒有被interrupted呢");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("我是 "+Thread.currentThread().getName()+",我被interrupted了");
            }
        },"thread");
        thread.start();
        Thread.sleep(300);
        flag = true;
    }
}

Java多線程的示例分析

2.使用Thread的interrupted來中斷
package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 9:59;
 */
public class ThreadDemo11 {
//    private static boolean flag = false;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()){
                    System.out.println("我是 : " + Thread.currentThread().getName() + ",我還沒有被interrupted呢");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
//                        e.printStackTrace();
                        break;
                    }
                }
                System.out.println("我是 "+Thread.currentThread().getName()+",我被interrupted了");
            }
        },"thread");
        thread.start();
        Thread.sleep(300);
        thread.interrupt();
//        flag = true;
    }
}

Java多線程的示例分析

3.Thraed.interrupted()方法和Threaed.currentThread().interrupt()的區(qū)別

Thread.interrupted()方法第一次接收到終止的狀態(tài)后,之后會將狀態(tài)復位,Thread.interrupted()是靜態(tài)的,是全局的。

Threaed.currentThread().interrupt()只是普通的方法。

Thraed.interrupted()方法

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 10:32;
 */
public class ThreadDemo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() ->{
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.interrupted());
            }
        });
        thread.start();
        thread.interrupt();
    }
}

Java多線程的示例分析

Threaed.currentThread().interrupt()

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 10:32;
 */
public class ThreadDemo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() ->{
            for (int i = 0; i < 10; i++) {
//                System.out.println(Thread.interrupted());
                System.out.println(Thread.currentThread().isInterrupted());
            }
        });
        thread.start();
        thread.interrupt();
    }
}

Java多線程的示例分析

yield()方法

讓出CPU的執(zhí)行權(quán)

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 11:47;
 */
public class ThreadDemo15 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                Thread.yield();
                System.out.println("thread1");
            }
        });
        thread1.start();
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println("thread2");
            }
        });
        thread2.start();
    }
}

Java多線程的示例分析

線程的狀態(tài)

Java多線程的示例分析

打印出線程的所有的狀態(tài),所有的線程的狀態(tài)都在枚舉中。?

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 11:06;
 */
public class ThreadDemo14 {
    public static void main(String[] args) {
        for (Thread.State state: Thread.State.values()) {
            System.out.println(state);
        }
    }
}

Java多線程的示例分析

  • NEW 創(chuàng)建了線程但是還沒有開始工作

  • RUNNABLE 正在Java虛擬機中執(zhí)行的線程

  • BLOCKED 受到阻塞并且正在等待某個監(jiān)視器的鎖的時候所處的狀態(tài)

  • WAITTING 無限期的等待另一個線程執(zhí)行某個特定操作的線程處于這個狀態(tài)

  • TIME_WAITTING 有具體等待時間的等待

  • TERMINATED 已經(jīng)退出的線程處于這種狀態(tài)

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 11:06;
 */
class TestThreadDemo{
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println(thread.getState());
        thread.start();
        System.out.println(thread.getState());
        Thread.sleep(100);
        System.out.println(thread.getState());
        thread.join();
        System.out.println(thread.getState());
    }
}

Java多線程的示例分析

線程的優(yōu)先級

在Java中線程 的優(yōu)先級分為1 ~ 10 一共十個等級

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-11;
 * time: 21:22;
 */
public class ThreadDemo9 {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("t1");
                }
            });
            //最大優(yōu)先級
            t1.setPriority(10);
            t1.start();
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("t2");
                }
            });
            //最小優(yōu)先級
            t2.setPriority(1);
            t2.start();
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("t3");
                }
            });
            t3.setPriority(1);
            t3.start();
        }
    }
}

Java多線程的示例分析

線程的優(yōu)先級不是絕對的,只是給程序的建議。

線程之間的優(yōu)先級具有繼承的特性,如果A線程啟動了B線程,那么B的線程的優(yōu)先級與A是一樣的。?

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-11;
 * time: 20:46;
 */
class ThreadA extends Thread{
    @Override
    public void run() {
        System.out.println("ThreadA優(yōu)先級是:" + this.getPriority());
        ThreadB threadB = new ThreadB();
        threadB.start();
    }
}
class ThreadB extends ThreadA{
    @Override
    public void run() {
        System.out.println("ThreadB的優(yōu)先級是:" + this.getPriority());
    }
}
public class ThreadDemo7 {
    public static void main(String[] args) {
        System.out.println("main線程開始的優(yōu)先級是:" + Thread.currentThread().getPriority());   
        System.out.println("main線程結(jié)束的優(yōu)先級是:" + Thread.currentThread().getPriority());
        ThreadA threadA = new ThreadA();
        threadA.start();
    }
}

Java多線程的示例分析

再看?

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-11;
 * time: 20:46;
 */
class ThreadA extends Thread{
    @Override
    public void run() {
        System.out.println("ThreadA優(yōu)先級是:" + this.getPriority());
        ThreadB threadB = new ThreadB();
        threadB.start();
    }
}
class ThreadB extends ThreadA{
    @Override
    public void run() {
        System.out.println("ThreadB的優(yōu)先級是:" + this.getPriority());
    }
}
public class ThreadDemo7 {
    public static void main(String[] args) {
        System.out.println("main線程開始的優(yōu)先級是:" + Thread.currentThread().getPriority());
        Thread.currentThread().setPriority(9);
        System.out.println("main線程結(jié)束的優(yōu)先級是:" + Thread.currentThread().getPriority());
        ThreadA threadA = new ThreadA();
        threadA.start();
    }
}

結(jié)果為?

Java多線程的示例分析
守護線程

Java中有兩種線程:一種是用戶線程,一種就是守護線程。

什么是守護線程?守護線程是一種特殊的線程,當進程中不存在用戶線程的時候,守護線程就會自動銷毀。典型的守護線程就是垃圾回收線程,當進程中沒有了非守護線程,則垃圾回收線程也就沒有存在的必要了。

Daemon線程的作用就是為其他線程的運行提供便利的。?

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-11;
 * time: 21:06;
 */
public class ThreadDemo8 {
    static private int i = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    i++;
                    System.out.println(i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        //設置守護線程
        thread.setDaemon(true);
        thread.start();
        Thread.sleep(5000);
        System.out.println("我是守護線程thread 當用戶線程執(zhí)行完成后 我也就銷毀了?哭了");
    }
}

Java多線程的示例分析

注意:守護線程的設置必須放在start()之前,否則就會報錯。

Java多線程的示例分析

在守護線程中創(chuàng)建的線程默認也是守護線程。

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 9:35;
 */
public class ThreadDemo10 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            Thread thread2 = new Thread(() -> {
            },"thread2");
            System.out.println("thread2是守護線程嗎?:" + thread2.isDaemon());
        },"thread1");
        System.out.println("thread1是守護線程嗎?:" + thread1.isDaemon());
        //thread1.setDaemon(true);
        thread1.start();
       // System.out.println("thread1是守護線程嗎?:" + thread1.isDaemon());
    }
}

Java多線程的示例分析

再看?

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 9:35;
 */
public class ThreadDemo10 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            Thread thread2 = new Thread(() -> {
            },"thread2");
            System.out.println("thread2是守護線程嗎?:" + thread2.isDaemon());
        },"thread1");
        System.out.println("thread1是守護線程嗎?:" + thread1.isDaemon());
        thread1.setDaemon(true);
        thread1.start();
        System.out.println("thread1是守護線程嗎?:" + thread1.isDaemon());
    }
}

Java多線程的示例分析

線程組

為了便于對某些具有相同功能的線程進行管理,可以把這些線程歸屬到同一個線程組中,線程組中既可以有線程對象,也可以有線程組,組中也可以有線程。使用線程模擬賽跑

public class ThreadDemo5 {
    //線程模擬賽跑(未使用線程分組)
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "到達了終點");
            }
        }, "選手一");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "到達了終點");
            }
        }, "選手二");
        t1.start();
        t2.start();
        System.out.println("所有選手到達了終點");
    }
}

運行結(jié)果:

Java多線程的示例分析

不符合預期效果,就可以使用線程組來實現(xiàn)

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-11;
 * time: 18:24;
 */
class ThreadGroup1 {
    //線程分組模擬賽跑
    public static void main(String[] args) {
        ThreadGroup threadGroup = new ThreadGroup("Group");
        Thread t1 = new Thread(threadGroup, new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("選手一到達了終點");
            }
        });
        Thread t2 = new Thread(threadGroup, new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("選手二到達了終點");
            }
        });
        t2.start();
        t1.start();
        while (threadGroup.activeCount() != 0) {
        }
        System.out.println("所有選手到達了終點");
    }
}

Java多線程的示例分析

線程組常用的方法

Java多線程的示例分析

線程安全問題

來看單線程情況下讓count分別自增和自減10000次

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 12:03;
 */
class Counter {
    private static int count = 0;
    public void increase(){
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }
    public void decrease(){
        for (int i = 0; i < 10000; i++) {
            count--;
        }
    }
    public int getCount(){
        return count;
    }
}
public class ThreadDemo16 {
    public static void main(String[] args) {
        //單線程
        Counter counter = new Counter();
        counter.increase();
        counter.decrease();
        System.out.println(counter.getCount());
    }
}

結(jié)果符合預期

Java多線程的示例分析

如果想使程序的執(zhí)行速度快,就可以使用多線程的方式來執(zhí)行。在來看多線程情況下的問題

public class ThreadDemo16 {
    public static void main(String[] args) throws InterruptedException {
        //多線程情況下
        Counter counter = new Counter();
        Thread thread1 = new Thread(()->{
            counter.decrease();
        });
        Thread thread2 = new Thread(()->{
            counter.increase();
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(counter.getCount());
                /*
        //單線程
        Counter counter = new Counter();
        counter.increase();
        counter.decrease();
        System.out.println(counter.getCount());
         */
    }
}

執(zhí)行結(jié)果:

Java多線程的示例分析

Java多線程的示例分析

Java多線程的示例分析

每次的執(zhí)行結(jié)果是不一樣的。這就是多線程的不安全問題

Java多線程的示例分析

預期的結(jié)果是0,但結(jié)果卻不是。線程不安全問題的原因:

  • 1.CPU的搶占式執(zhí)行

  • 2.多個線程共同操作一個變量

  • 3.內(nèi)存可見性

  • 4.原子性問題

  • 5.編譯器優(yōu)化(指令重排)

多個線程操作同一個變量

如果多個線程操作的不是一個變量,就不會發(fā)生線程的不安全問題,可以將上面的代碼修改如下:?

public class ThreadDemo16 {
    static int res1 = 0;
    static int res2 = 0;
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                res1 = counter.getCount();
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                res2 = counter.getCount();
            }
        });
        System.out.println(res1 + res2);
/*
        //多線程情況下
        Counter counter = new Counter();
        Thread thread1 = new Thread(()->{
            counter.decrease();
        });
        Thread thread2 = new Thread(()->{
            counter.increase();
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(counter.getCount());
        */
                /*
        //單線程
        Counter counter = new Counter();
        counter.increase();
        counter.decrease();
        System.out.println(counter.getCount());
         */
    }
}

這樣就可以了:

Java多線程的示例分析

內(nèi)存不可見問題:看下面的代碼,是不是到thread2執(zhí)行的時候,就會改變num的值,從而終止了thread1呢?

package ThreadDeom;
import java.util.Scanner;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 13:03;
 */
public class ThreadDemo17 {
    private static int num = 0;
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (num == 0){}
            }
        });
        thread1.start();
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Scanner scanner = new Scanner(System.in);
                System.out.println("輸入一個數(shù)字來終止線程thread1");
                num = scanner.nextInt();
            }
        });
        thread2.start();
    }
}

結(jié)果是不能的:

Java多線程的示例分析

輸入一個數(shù)字后回車,并沒有讓thread1的循環(huán)結(jié)束。這就是內(nèi)存不可見的問題。

原子性的問題

上面的++和–操作其實是分三步來執(zhí)行的

Java多線程的示例分析

假設在第二部的時候,有另外一個線程也來修改值,那么就會出現(xiàn)臟數(shù)據(jù)的問題了。

所以就會發(fā)生線程的不安全問題

編譯器優(yōu)化編譯器的優(yōu)化會打亂原本程序的執(zhí)行順序,就有可能導致線程的不安全問題發(fā)生。在單線程不會發(fā)生線程的不安全問題,在多線程就可能會不安全。

volatile關(guān)鍵字

可以使用volatile關(guān)鍵字,這個關(guān)鍵字可以解決指令重排和內(nèi)存不可見的問題。

Java多線程的示例分析

加上volatile關(guān)鍵字之后的運行結(jié)果

Java多線程的示例分析

但是volatile關(guān)鍵字不能解決原子性的問題?:

package ThreadDeom;
/**
 * user:ypc;
 * date:2021-06-12;
 * time: 14:02;
 */
class Counter1 {
    private static volatile int count = 0;
    public void increase() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }
    public void decrease() {
        for (int i = 0; i < 10000; i++) {
            count--;
        }
    }
    public int getCount() {
        return count;
    }
}
public class ThreadDemo18 {
    public static void main(String[] args) throws InterruptedException {
        Counter1 counter1 = new Counter1();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                counter1.decrease();
            }
        });
        Thread thread2 = new Thread(() -> {
            counter1.increase();
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(counter1.getCount());
    }
}

Java多線程的示例分析

Java多線程的示例分析

感謝各位的閱讀!關(guān)于“Java多線程的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI