併發

1、線程實現的方式java

一、實現Runnable接口並編寫run()方法併發

二、繼承Thread類並覆蓋run()方法ide

三、前二者都不返回任何值,若是你但願任務在完成時能返回一個值,那麼就須要實現Callable接口.this

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadTest
{
    public static void main(String[] args)
    {
        try
        {
            Future<String> result = getDataFromRemote();
            System.out.println(result.get());
        } catch(InterruptedException | ExecutionException e)
        {
            e.printStackTrace();
        }
    }

    public static Future<String> getDataFromRemote()
    {
        ExecutorService service = Executors.newCachedThreadPool();
        return service.submit(new Callable<String>()
        {
            @Override
            public String call() throws Exception
            {
                System.out.println("getDataFromRemote is ing...");
                try
                {
                    Thread.sleep(2000);
                } catch(InterruptedException e)
                {
                    e.printStackTrace();
                }
                return "ok";
            }
        });
    }
}

//output
getDataFromRemote is ing...
ok

2、一些概念簡介:編碼

Thread.yield():對線程調度器的一種建議,它在聲明:「我已經執行完生命週期中最重要的部分了,此刻正是切換給其餘任務執行一段時間的大好時機」。spa

Thread.sleep():休眠,不釋放對CPU的佔用;Object對象的wait()方法:釋放CPU線程

getPriority():優先級code

後臺線程(daemon):也叫守護線程,是指在程序運行的時候在後臺提供一些通用服務的線程,而且這種線程並不屬於程序中不可或缺的部分。當全部非後臺線程結束,程序被終止,同時進程中的全部後臺線程也會被殺死。典型的就是 垃圾回收。對象

要將一個線程設置爲後臺線程,則調用setDaemon(true)便可、blog

t.join():等待一段時間直到線程t結束,原線程才繼續執行

捕獲異常:因爲線程的本質特性,使得不能捕獲從線程逃逸的異常。一旦異常逃出任務的run()方法後,就會向外傳播到控制檯。除非採起特殊的方式捕獲這些異常。

package threadpool;

public class ExceptionThread1 implements Runnable
{
    @Override
    public void run()
    {
        throw new RuntimeException();
    }

    public static void main(String[] args)
    {
        try
        {
            Thread thread = new Thread(new ExceptionThread1());
            thread.start();
        } catch(Exception e)
        {
        }
    }
}

//output

Exception in thread "Thread-0" java.lang.RuntimeException
    at threadpool.ExceptionThread1.run(ExceptionThread1.java:9)
    at java.lang.Thread.run(Unknown Source)

爲了解決這個問題,java se5以後的新街口Thread.UncaughtExceptionHandler能夠解決這個問題。

package threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class ExceptionThread implements Runnable
{

    @Override
    public void run()
    {
        Thread t = Thread.currentThread();
        System.out.println("run() by " + t);
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        throw new RuntimeException();
    }

    public static void main(String[] args)
    {
        try
        {
            ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
            exec.execute(new ExceptionThread());
        } catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}

class HandlerThreadFactory implements ThreadFactory
{
    @Override
    public Thread newThread(Runnable r)
    {
        System.out.println(this + " creating new Thread");
        Thread t = new Thread(r);
        System.out.println(" created " + t);
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        return t;
    }
    
}

class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler
{
    @Override
    public void uncaughtException(Thread t, Throwable e)
    {
        System.out.println("caught " + e);
    }
}
//output

threadpool.HandlerThreadFactory@16acdd1 creating new Thread
created Thread[Thread-0,5,main]
eh = threadpool.MyUncaughtExceptionHandler@facf0b
run() by Thread[Thread-0,5,main]
eh = threadpool.MyUncaughtExceptionHandler@facf0b
threadpool.HandlerThreadFactory@16acdd1 creating new Thread
created Thread[Thread-1,5,main]
eh = threadpool.MyUncaughtExceptionHandler@10721b0
caught java.lang.RuntimeException

 

3、線程同步的方式

所謂死鎖: 是指兩個或兩個以上的進程在執行過程當中,因爲競爭資源或者因爲彼此通訊而形成的一種阻塞的現象,若無外力做用,它們都將沒法推動下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱爲死鎖進程。

死鎖產生的四個條件:

1)互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程佔用。若是此時還有其它進程請求資源,則請求者只能等待,直至佔有資源的進程用畢釋放。
2)請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程佔有,此時請求進程阻塞,但又對本身已得到的其它資源保持不放。
3)不剝奪條件:指進程已得到的資源,在未使用完以前,不能被剝奪,只能在使用完時由本身釋放。
4)環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……,Pn正在等待已被P0佔用的資源。
基本上全部的併發模式在解決縣城衝突問題的時候,都是採用序列化訪問共享的方案

一、Synchronized

全部對象都自動含有單一的鎖(也稱爲監視器)。當在對象上調用其任何synchronzised方法的時候,此對象都被加鎖,這時候該對象的其餘synchronzised方法只有等到前一個方法調用完畢並釋放鎖以後才能被調用。因此,對於某個特定對象來講,其全部synchronzised方法共享同一個鎖。這能夠被用來防止多個任務同時訪問被編碼爲對象內存。

針對每一個類,也有一個鎖。因此synchronized static 方法能夠在類的範圍內防止對static數據的併發訪問。

二、使用顯示的Lock對象

Java SE5的java.util.concurrent類庫還包含有定義在java.util.concurrent.locks中的顯示 互斥機制。Lock對象必須被顯示地建立、鎖定和釋放。所以,它與內建的鎖形式相比,代碼缺少優雅性。可是,對於解決某些類型的問題來講,它更加靈活。

class EvenGenerator extends IntGenerator
{
    private int currentEvenValue = 0;
    private Lock lock = new ReentrantLock();
    @Override
    public int next()
    {
        lock.lock();
        try
        {
            ++currentEvenValue;
            Thread.yield();
            ++currentEvenValue;
            return currentEvenValue;
        }
        finally
        {
            lock.unlock();
        }
    }
}

 

當使用Lock對象時,對lock()的調用,必須放置在finally子句中帶有unlock()的try-finally語句中、

return必須在try子句中,以確保unlock()不會過早發生。

若是使用synchronized,某些事務失敗了,就會拋出一個異常。而又沒法去作任何清理工做,以維護系統使其處於良好狀態。

ReentrantLock容許你嘗試獲取但最終未獲取鎖,這樣若是其餘人已經獲取了這個鎖,那你就能夠決定離開去執行其餘一些事情,而不是等待直至這個鎖被釋放。

lock.tryLock();

lock.tryLock(2, TimeUnit.SECONDS);

4、線程本地存儲--根除對變量的共享

線程本地存儲是一種自動化機制,能夠爲使用相同變量的每一個不一樣的線程都建立不一樣的存儲。

ThreadLocal類實現,一般看成靜態域存儲。在建立ThreadLocal時,你只能經過get()和set()方法來訪問該對象的內容。實質就是每一個單獨的線程都被分配了本身的存儲,由於它們

每一個都須要跟蹤本身的計數值,從而實現了線程間的數據隔離。

相關文章
相關標籤/搜索