C語言中文網 目錄

Java非線程安全問題的解決方法

在上節《多線程之間訪問實例變量》中出現了一個術語——非線程安全。非線程安全主要是指多個線程對同一個對象中的同一個實例變量進行操作時會出現值被更改、值不同步的情況,進而影響程序的執行流程。下面用一個示例來學習一下如何解決非線程安全問題。

本案例模擬了多線程下的用戶登錄驗證功能。首先編寫一個類實現驗證功能, LoginCheck 類的代碼如下:
package ch14;
public class LoginCheck
{
    private static String username; 
    private static String password; 
    public static void doPost(String _username,String _password)
    { 
        try
        { 
            username=_username; 
            if (username.equals("admin"))
            { 
                Thread.sleep(5000); 
            } 
            password=_password; 
            System.out.println("username="+username+"password="+password); 
        }
        catch(InterruptedException e)
        { 
            // TODO Auto-generated catch block 
            e.printStackTrace(); 
        } 
    } 
}

接下來創建線程類 LoginThreadA 和 LoginThreadB,這兩個線程都調用 LoginCheck 類進行登錄信息。其中 LoginThreadA 類的代碼如下:
package ch14;
public class LoginThreadA extends Thread
{
    public void run()
    { 
        LoginCheck.doPost("admin","admin"); 
    }
}

LoginThreadB 類的代碼如下:
package ch14;
public class LoginThreadB extends Thread
{ 
    public void run()
    { 
        LoginCheck.doPost("root","root"); 
    }
}

現在編寫主線程程序,分別創建 LoginThreadA 線程實例和 LoginThreadB 線程實現,然后啟動這兩個線程。主線程的代碼如下:
package ch14;
public class Test07
{
    public static void main(String[] args)
    {
        LoginThreadA a=new LoginThreadA();
        a.run();    //啟動線程LoginThreadA
        LoginThreadB b=new LoginThreadB();
        b.run();    //啟動線程LoginThreadB
    }
}

程序運行后的結果如下所示:
username=root password=admin
username=root password=root

從運行結果中可以看到用戶名 root 出現了這兩次,這是由于多個線程同時修改 username,導致值不一致的情況。

仔細查看代碼可以發現問題出現在兩個線程都會調用 doPost() 方法上。解決這個非線程安全問題的方法是使用 synchronized 關鍵字修飾 doPost() 方法,即不允許多個線程同時修改 doPost() 方法中的變量。更改代碼如下:
package ch14;
public class LoginCheck
{
    private static String username; 
    private static String password; 
    synchronized public static void doPost(String _username,String _password)
    { 
        try
        { 
            username=_username; 
            if (username.equals("admin"))
            { 
                Thread.sleep(5000); 
            } 
            password=_password; 
            System.out.println("username="+username+"password="+password); 
        }
        catch (InterruptedException e)
        { 
            // TODO Auto-generated catch block 
            e.printStackTrace(); 
        } 
    } 
}

再次運行主線程,此時將看到如下所示的結果,說明不存在“非線程安全”問題了。
username=admin password=admin
username=root password=root

精美而實用的網站,提供C語言、C++、STL、Linux、Shell、Java、Go語言等教程,以及socket、GCC、vi、Swing、設計模式、JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo
极速pk10开户