Java多線程

一:Java中三種多線程的實現方式

在Java中實現多線程有兩種途徑,

  • 繼承Thread類,重寫run方法,多線程啓動的方法,就是start方法。(單繼承的侷限)
public class TestThread extends Thread {
    private String name;

    public TestThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println(this.name + "-->" + i);
        }
    }

    public static void main(String[] args) {
        TestThread thread1 = new TestThread("線程1");
        TestThread thread2 = new TestThread("線程2");
        TestThread thread3 = new TestThread("線程3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
  • 實現Runnable接口,並且重寫run方法。多線程的啓動還是Thread的start方法。
public class TestRunnable implements Runnable {
    private String name;

    public TestRunnable(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println(this.name + "-->" + i);
        }
    }

    public static void main(String[] args) {
        TestRunnable thread1 = new TestRunnable("線程1");
        TestRunnable thread2 = new TestRunnable("線程2");
        TestRunnable thread3 = new TestRunnable("線程3");
        new Thread(thread1).start();
        new Thread(thread2).start();
        new Thread(thread3).start();
    }
}

兩種方式的區別:

  • 實現Runnable接口解決了單繼承的侷限,Thread類實現了Runable接口
  • 線程資源共享,Runnable更好的詮釋了數據共享,多線程訪問同一資源
    public static void main(String[] args) {
        TestRunnable thread1 = new TestRunnable("線程1");
        new Thread(thread1).start();
        new Thread(thread1).start();
        new Thread(thread1).start();
    }

jdk1.5的新特性,線程執行完接收返回值,也是線程實現的第三種方式,

package com.java.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class TestCallable implements Callable<String> {
    private int ticket = 10;

    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            if (ticket > 0) {
                System.out.println("賣票,票數=" + ticket--);
            }
        }
        return "票賣完了";
    }

    public static void main(String[] args) throws Exception {
        TestCallable testCallable1 = new TestCallable();
        TestCallable testCallable2 = new TestCallable();
        FutureTask<String> futureTask1 = new FutureTask<>(testCallable1);
        FutureTask<String> futureTask2 = new FutureTask<>(testCallable2);
        new Thread(futureTask1).start();
        new Thread(futureTask2).start();
        System.out.println("futureTask1 = " + futureTask1.get());
        System.out.println("futureTask2 = " + futureTask2.get());
    }
}

二:線程的命名與取得,Thread.currentThread().getName(),線程能夠自動命名

public class TestRunnable implements Runnable {
    private String name;

    public TestRunnable(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        TestRunnable thread1 = new TestRunnable("線程1");
        new Thread(thread1,"線程1").start();
        new Thread(thread1).start();
        new Thread(thread1,"線程3").start();
    }
}

每一個JVM啓動,至少啓動兩個線程

  • main線程,以及程序的子線程
  • gc線程,負責垃圾回收

三:線程的休眠

  •   Thread.sleep(1000); 有先後差別

四:線程的優先級Thread類裏面提供的兩個方法,以及三個常量

    public static void main(String[] args) {
        TestThread thread1 = new TestThread("線程1");
        TestThread thread2 = new TestThread("線程2");
        TestThread thread3 = new TestThread("線程3");
        thread1.setPriority(MAX_PRIORITY);
        thread2.setPriority(MIN_PRIORITY);
        thread3.setPriority(NORM_PRIORITY);
        thread1.start();
        thread2.start();
        thread3.start();
    }

五:總結

  • 主線程屬於中等優先級,
  • Thread.currentThread()可以獲取當前線程的對象。

六:同步問題

多個線程訪問同一個資源需要考慮的問題,4個人賣5張票,在判斷和修改是分開執行的,最後一張票出現了資源的延遲,

 

如何解決同步的問題

當有線程在執行的時候,其他的線程先等待。在Java中要想實現線程的同步需要使用synchronized關鍵字。

使用方式,

  • 同步代碼塊
  • 同步方法

Java中有四種代碼塊,普通代碼塊,構造塊,靜態塊,同步塊。

  • 以下是同步代碼塊,

  • 以下是同步方法,
public class TestSynchronized implements Runnable {
    private int ticket = 50;

    @Override
    public void run() {
        try {
            for (int i = 0; i < 200; i++) {
                //賣票的過程
                if (sell()) {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public synchronized boolean sell() throws InterruptedException {
        if (ticket > 0) {
//            Thread.sleep(200);
            System.out.println(Thread.currentThread().getName() + "...票數=" + this.ticket--);
            return false;
        } else {
            return true;
        }
    }

    public static void main(String[] args) {
        TestSynchronized thread0 = new TestSynchronized();
        new Thread(thread0,"票販子A").start();
        new Thread(thread0,"票販子B").start();
        new Thread(thread0,"票販子C").start();
        new Thread(thread0,"票販子D").start();
    }
}

死鎖:是一個線程對象等待另一個線程對象執行完畢後的操作結果,同步過多可能發生死鎖。

多個線程訪問一個資源需要考慮哪些問題,

  • 同步問題,可以使用同步代碼塊,也可以使用同步方法
  • 過多的使用同步可能造成死鎖

七:生產者和消費者

  • 生產者負責生產數據,消費者負責取走數據
  • 生產者每生產一組數據,消費者就取走一組數據

等待與喚醒,

  • super.wait();
  • super.notify();

sleep和wait得區別,

  • sleep是Thread類的方法,wait是Object類的方法
  • sleep可以設置休眠時間,時間一到自動喚醒,而wait需要notify去喚醒。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章