2013-02-25 35 views
6

Tôi chỉ hỏi trong phối cảnh luồng ... có thể đã trả lời nhiều lần nhưng hãy giúp tôi hiểu điều này.Biến tĩnh so với Biến động

Với tài liệu tham khảo để đăng bài viết Volatile Vs Static in java

hỏi một giá trị biến tĩnh cũng sẽ là một giá trị cho tất cả các chủ đề, thì tại sao chúng ta nên đi cho dễ bay hơi? Tôi tìm thấy ví dụ sau đây:

public class VolatileExample { 
public static void main(String args[]) { 
    new ExampleThread("Thread 1 ").start(); 
    new ExampleThread("Thread 2 ").start(); 
} 

} 
class ExampleThread extends Thread { 
private static volatile int testValue = 1; 
public ExampleThread(String str){ 
    super(str); 
} 
public void run() { 
    for (int i = 0; i < 3; i++) { 
     try { 
      System.out.println(getName() + " : "+i); 
      if (getName().compareTo("Thread 1 ") == 0) 
      { 
       testValue++; 
       System.out.println("Test Value T1: " + testValue); 
      } 
      if (getName().compareTo("Thread 2 ") == 0) 
      { 
       System.out.println("Test Value T2: " + testValue); 
      }     
      Thread.sleep(1000); 
     } catch (InterruptedException exception) { 
      exception.printStackTrace(); 
      } 
     } 
     } 
     } 

Output:

Thread 1 : 0 
Test Value T1: 2 
Thread 2 : 0 
Test Value T2: 2 
Thread 1 : 1 
Test Value T1: 3 
Thread 2 : 1 
Test Value T2: 3 
Thread 1 : 2 
Test Value T1: 4 
Thread 2 : 2 
Test Value T2: 4 

Nếu tôi loại bỏ các tĩnh từ testValue, kết quả thu được:

Thread 1 : 0 
Test Value T1: 2 
Thread 2 : 0 
Test Value T2: 1 
Thread 1 : 1 
Test Value T1: 3 
Thread 2 : 1 
Test Value T2: 1 
Thread 1 : 2 
Test Value T1: 4 
Thread 2 : 2 
Test Value T2: 1 

Tại sao chủ đề 2 không đọc giá trị được cập nhật? Nếu nó phải được thực hiện tĩnh, whats việc sử dụng dễ bay hơi?

Ai đó có thể cung cấp liên kết đến một ví dụ dễ bay hơi mà biến đó không khai báo tĩnh.

Cảm ơn

+1

Các chấp nhận câu trả lời trên bài đăng bạn đã liên kết để trả lời câu hỏi của bạn. –

+2

Đọc phần còn lại của câu trả lời - đặc biệt. bit về ** tĩnh dễ bay hơi ** .. – Nim

+0

'static' =/=' final'. –

Trả lời

4

Vấn đề là ++ không phải là nguyên tử. Mã nên sử dụng AtomicInteger thay thế. Với biến số static, cả hai luồng đều cố gắng cập nhật cùng một giá trị và ++ thực sự là 3 thao tác: nhận, +1 và lưu trữ. Điều này có nghĩa rằng có một điều kiện chủng tộc giữa cả hai chủ đề và họ đang ghi đè lên nhau.

Tại sao chuỗi 2 không đọc giá trị được cập nhật? Nếu nó phải được thực hiện tĩnh, whats việc sử dụng dễ bay hơi?

staticvolatile làm những việc khác nhau. static làm cho trường được liên kết với lớp đó trái với đối tượng đối tượng. volatile bắt buộc phải đọc hoặc ghi trường để vượt qua rào cản bộ nhớ. Điều này cho phép nhiều chủ đề đọc và cập nhật một trường chung nhưng điều này không không bảo vệ bạn khỏi nhiều thao tác. Nếu bạn tạo biến không phải là tĩnh thì bạn sẽ không cần volatile vì mỗi chuỗi sẽ hoạt động với trường hợp riêng của trường đó.

Bạn nên sử dụng AtomicInteger.Đây kết thúc tốt đẹp một volatile int mà còn cung cấp xử lý đặc biệt của hoạt động increment:

private static AtomicInteger testValue = new AtomicInteger(1); 
... 
testValue.incrementAndGet(); 

Ai đó có thể cung cấp cho liên kết đến một ví dụ tốt về ổn định nơi biến được không khai báo tĩnh.

Bạn sẽ cần một volatile trên trường không tĩnh khi được nhiều chuỗi chia sẻ. Ví dụ: nếu bạn đã di chuyển testValue lên trong lớp VolatileExample và sau đó chuyển cùng một phiên bản của lớp VolatileExample thành cả hai luồng để chúng có thể truy cập testValue.

+0

Cảm ơn bạn đã có cái nhìn sâu sắc có giá trị, tôi sẽ kiểm tra tương tự, giữ biến ở nơi khác. – Dhananjay

+0

Chỉ cần nhắc lại, bạn không thể làm một '+ +' trên một 'biến động 'bất kể nó có tĩnh hay không @Dhananjay. – Gray

+0

tôi đã thử đặt biến bên ngoài lớp Runnable.
' Tài khoản công khai {số dư công khai gấp đôi = 0; chính void tĩnh chính (String ... s) { Tài khoản aAccount = new Account(); DepositThread aDepositThread1 = new DepositThread (aAccount); Thread thread1 = new Thread (aDepositThread1, "thread1"); DepositThread1 aDepositThread2 = new DepositThread1 (aAccount); Thread thread2 = new Thread (aDepositThread2, "thread2"); thread1.start(); thread2.start(); } } ' Nhưng nếu chúng ta truyền cùng một đối tượng trong hai chuỗi, Nó sẽ nhận được giá trị cập nhật anyways? – Dhananjay

4

Việc sử dụng volatile là để đảm bảo rằng tất cả các chủ đề thấy cùng một giá trị cùng một lúc. Về cơ bản nó nói rằng biến này không bao giờ nên được lưu trữ.

Rất khó để chứng minh bằng mã vì các chiến lược lưu bộ nhớ cache thay đổi từ CPU sang CPU và từ JRE sang JRE.

Điều gì volatile được nói đến JRE là Nếu bạn đã bao giờ bị cám dỗ để cache giá trị này bởi vì bạn nghĩ rằng bạn có thể làm cho mã chạy nhanh hơn một chút bằng cách làm như vậy ... DONT! ... Tôi biết MUCH nhiều hơn về lập trình hơn bạn và tôi biết mà không có một cái bóng nghi ngờ rằng nếu bạn làm bạn sẽ phá vỡ mã của tôi..

0

Trong trường hợp này, khi bạn xóa biến thể static, bạn đã thay đổi biến, bởi vì hiện tại, mỗi ExampleThread có giá trị lưu trữ riêng cho mỗi chủ đề.

Ý nghĩa của static modifier:

Đôi khi, bạn muốn có biến chung cho tất cả các đối tượng. Điều này được thực hiện với công cụ sửa đổi tĩnh. Các trường có công cụ sửa đổi tĩnh trong khai báo của chúng được gọi là các trường tĩnh hoặc các biến lớp. Chúng được kết hợp với lớp, thay vì với bất kỳ đối tượng nào. Mỗi cá thể của lớp chia sẻ một biến lớp, mà là ở một vị trí cố định trong bộ nhớ. Bất kỳ đối tượng có thể thay đổi giá trị của một biến lớp ...

tham khảo: Understanding Instance and Class Members

Về volatile, nếu bạn thử một loại khác nhau của kiểm tra, chuyển biến testValue đến lớp VolatileExample, như thế này:

public class VolatileExample { 
    private volatile int testValue = 1; 
... 
} 

Sau đó, loại bỏ các testVariable từ ExampleThread và chạy mã. Sản lượng của nó sẽ giống như đầu ra.

Ý nghĩa của volatile modifier:

Sử dụng các biến không ổn định làm giảm nguy cơ lỗi bộ nhớ nhất quán, bởi vì bất kỳ ghi vào một biến không ổn định thiết lập một xảy ra-trước khi mối quan hệ với sau này đọc của biến tương tự. Điều này có nghĩa rằng những thay đổi cho một biến không ổn định là luôn hiển thị với chủ đề khác

tham khảo: Atomic Access

0

câu hỏi cuối cùng của bạn "Ai đó có thể cung cấp cho liên kết đến một ví dụ tốt về ổn định nơi biến được không khai báo tĩnh. " đã hiểu rõ khái niệm này và tôi đã đưa ra một ví dụ.

public class VolatileExample { 

    // public static volatile int testValue = 1; 
    public int nonstatic=8; 
    public static void main(String args[]) { 
     VolatileExample volatileExample=new VolatileExample(); 
     new ExampleThread("Thread 1 ",volatileExample).start(); 
     new ExampleThread("Thread 2 ",volatileExample).start(); 
    } 

} 
class ExampleThread extends Thread { 
VolatileExample volatileExample; 
    public ExampleThread(String str,VolatileExample volatileExample){ 
     super(str); 
     this.volatileExample=volatileExample; 
    } 
    public void run() { 
     for (int i = 0; i < 3; i++) { 
      try { 
       if (getName().compareTo("Thread 1 ") == 0) 
       { 
        volatileExample.nonstatic++; 
        System.out.println("Test Value T1: " + volatileExample.nonstatic); 


       } 
       if (getName().compareTo("Thread 2 ") == 0) 
       { 
        System.out.println("Test Value T2: " + volatileExample.nonstatic); 
        Thread.sleep(1); 
       } 
       // Thread.sleep(1000); 
      } catch (InterruptedException exception) { 
       exception.printStackTrace(); 
      } 
     } 
    } 
} 

bây giờ vui lòng xem thay đổi bằng cách đặt công khai int nonstatic = 8; dễ bay hơi

Tiếp theo sẽ là đầu ra khi nó được làm không ổn định,

Kiểm tra Giá trị T1: 9 Kiểm tra Giá trị T1: 10 Kiểm tra Giá trị T1: 11 Kiểm tra Giá trị T2: 11 Kiểm tra Giá trị T2: 11 Kiểm tra Giá trị T2: 11

Process xong với mã exit 0

Sau đây là kết quả nếu nó được làm bằng non-volatile: kiểm tra giá trị T1: 9 kiểm tra giá trị T2 : 9 Kiểm tra Giá trị T1: 10 Kiểm tra Giá trị T1: 11 Kiểm tra Giá trị T2: 11 Kiểm tra Giá trị T2: 11

Process xong với mã exit 0

Observation: Kể từ khi từ khóa volatile làm cho thread để trực tiếp ghi nó vào bộ nhớ chính, luồng sẽ trở lại nhanh hơn cho vòng lặp do đó khi nó được tạo ra dễ bay hơi, thread1 hoàn thành nhiệm vụ của nó nhanh hơn và quay trở lại vòng lặp ngay cả trước khi thread2 bắt đầu lượt của nó.

Ở phía bên kia, làm cho nó không bay hơi, làm cho các chủ đề để cập nhật bộ nhớ cache locl của nó và sau đó báo cáo nó vào bộ nhớ chính ... vì vậy trong chu kỳ này, thread2 bước vào cuộc đua.

Lưu ý PLz, tôi có biến "không tĩnh" trong lớp VolatileExample không có trong ExampleThread để chứng minh điều này.

Câu hỏi khác của bạn là: Tại sao chuỗi 2 không đọc giá trị được cập nhật? Nếu nó phải được thực hiện tĩnh, whats việc sử dụng dễ bay hơi?

Vâng, nếu u làm cho nó testvalue không tĩnh, sau đó không có gì của nó, nhưng hai đối tượng khác nhau thread1 và thread2 của lớp ExampleThread làm việc trên riêng của họ varibles testvalue .... doesnt rất dễ bay hơi thực sự quan trọng ..