2012-01-16 30 views

Trả lời

13

Lựa chọn hai loại này không được phụ thuộc vào hiệu suất. Lựa chọn chính cho AtomicInteger là nếu bạn muốn đạt được an toàn luồng với các phép toán trên số nguyên.

Tuy nhiên sự khác biệt về hiệu suất có thể phụ thuộc mạnh vào hệ điều hành được chọn, vì việc triển khai chi tiết các hoạt động nguyên tử phụ thuộc vào hệ điều hành.

+3

+1. AtomicInteger cũng cung cấp một số nguyên có thể thay đổi giá rẻ, ngay cả trong trường hợp sử dụng không đồng thời. –

+0

-1: AtomicInteger tồn tại chủ yếu vì lý do hiệu suất (để triển khai cấu trúc dữ liệu không có khóa). Nếu an toàn thead là mối quan tâm duy nhất, bạn chỉ có thể sử dụng đồng bộ hóa. –

+2

@MichaelBorgwardt: chỉ vì an toàn luồng có thể thực hiện với việc đồng bộ hóa không có nghĩa là AtomicInteger không cung cấp các hoạt động số nguyên an toàn. Điểm của câu trả lời là hiệu suất thô của Integer và AtomicInteger không phải là điều hướng dẫn sự lựa chọn của cái này hay cái kia. Những gì hướng dẫn lựa chọn là mục đích sử dụng: chúng ta có cần một số nguyên an toàn có thể thay đổi được không, hay chúng ta chỉ muốn rap một số nguyên vào một đối tượng bất biến? –

1

Khác với phí đồng bộ hóa rất nhỏ, không.

5

Vâng, nếu bạn sử dụng nó trong môi trường đa luồng, ví dụ: truy cập, sau đó bạn phải synchronize truy cập vào Integer

public final class Counter { 
    private long value = 0; 
    public synchronized long getValue() { 
    return value; 
    } 

    public synchronized long increment() { 
    return ++value; 
    } 
} 

Trong khi bạn có thể có hiệu suất tốt hơn với AtomicInteger mà không cần đồng bộ hóa

public class NonblockingCounter { 
    private AtomicInteger value; 

    public int getValue() { 
     return value.get(); 
    } 

    public int increment() { 
     return value.incrementAndGet(); 
    } 
} 

Đề xuất đọc http://cephas.net/blog/2006/09/06/atomicinteger/

EDIT sử dụng incrementAndGet

+0

Tại sao không sử dụng incrementAndGet? –

+0

bạn có nghĩa là [getAndIncrement] (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html#getAndIncrement())? Vâng, câu hỏi tốt thưa ông, tôi đoán tôi đã quá nhanh và lười biếng. – bpgergo

+0

Không, ý tôi là incrementAndGet. getAndIncrement sẽ tương đương với trả về i ++. Nhưng đoạn mã đầu tiên của bạn trả về ++ i; –

3

AtomicInteger cho phép một số (không phải tất cả!) hoạt động mà nếu không sẽ yêu cầu đồng bộ hóa được thực hiện một cách không có khóa bằng cách sử dụng các hướng dẫn phần cứng đặc biệt. Điều này ảnh hưởng đến hiệu suất như thế nào là hơi phức tạp:

  • Trước tiên, việc tối ưu hóa vi mô sẽ chỉ quan trọng nếu hoạt động cụ thể này nằm trên đường dẫn quan trọng của ứng dụng của bạn.
  • Hướng dẫn phần cứng đặc biệt có thể không có sẵn trên nền tảng không chính thống, trong trường hợp này AtomicInteger có thể sẽ được triển khai bằng đồng bộ hóa.
  • JVM thường có thể tối ưu hóa chi phí khóa khi không có tranh chấp (ví dụ: một ứng dụng đơn luồng). Trong trường hợp đó, có lẽ không có sự khác biệt.
  • Nếu có sự tranh chấp khóa thấp đến trung bình (nghĩa là nhiều chủ đề, nhưng chúng chủ yếu làm những việc khác ngoài việc truy cập số nguyên đó), thuật toán không khóa sẽ hoạt động tốt hơn đồng bộ hóa.
  • Nếu có sự tranh chấp khóa nặng (nghĩa là rất nhiều chủ đề dành nhiều thời gian cố gắng truy cập số nguyên đó), đồng bộ hóa có thể hoạt động tốt hơn vì thuật toán không khóa được dựa trên việc liên tục thử lại thao tác khi nó không thành công do một sự va chạm.
+1

Chính xác các loại sự kiện tôi đã tìm kiếm. Cảm ơn. –

0

đi qua đăng tải ngày hôm nay nhưng muốn chia sẻ kết quả của tôi (Xin vui lòng không bình luận trên mã như tôi đã phải tay gõ các lớp sau như hệ thống tôi chạy này trên đã không được kết nối với internet :)

Bottom line đầu ra từ mã dưới đây là như sau:

Kết quả

ATOMIC: đã qua = 25.257 ms, ExpectedValue = 50000, FinalValue = 50000, đúng Kết quả nguyên thủy: đã qua = 25.257 ms, ExpectedValue = 50000, FinalValue = 48991, false

Đối với việc sử dụng của tôi trong ứng dụng cụ thể của tôi, tôi đã chọn sử dụng các giá trị nguyên tử cho các số trạng thái trong một lớp giám sát.Trong trường hợp ai đó muốn xem một số kết quả khó, tôi đã chọn đăng thông tin này.

Chúc bạn một ngày tuyệt vời!

Lớp học:

Tôi tạo ra một lớp học chính với một dài nguyên thủy và một nguyên tử các phương pháp tăng dài và accessor, một IncrementAtomicRunnable và một IncrementPrimitiveRunnable.

LongOverhead:

public class LongOverhead{ 
    AtomicLong atomicLong; 
    long primitiveLong; 

    public LongOverhead(){ 
    atomicLong = new AtomicLong(0l); 
    primitiveLong = 0l; 
    } 

    public void incrAtomicLong(){ 
    atomicLong.getAndAdd(1l); 
    } 

    public long getAtomicLong(){ 
    return atomicLong.get(); 
    } 

    public void incrPrimitiveLong(){ 
    primitiveLong++; 
    } 

    public long getPrimitiveLong(){ 
    return primitiveLong; 
    } 

    public static void main(String [] args){ 
    String template = "%s Results: Elapsed = %d ms, ExpectedValue = %d, FinalValue = %d, %b"; 

    int loopTotal = 1000; 
    int waitMilliseconds = 25; 
    int totalThreads = 50; 
    int expectedValue = loopTotal * totalThreads; 
    int whileSleep = 250; 

    LongOverhead atomic = new LongOverhead(); 
    LongOverhead primitive = new LongOverhead(); 

    List<Thread> atomicThreads = new ArrayList<>(); 
    List<Thread> primitiveThreads = new ArrayList<>(); 

    for(int x=0;x<totalThreads;x++){ 
     Thread a = new Thread(new IncrementalAtomicRunnable(atomic, loopTotal, waitMilliseconds), "AtomicIncr" + x); 
     atomicThreads.add(a); 

     Thread p = new Thread(new IncrementalPrimitiveRunnable(primitive, loopTotal, waitMilliseconds), "PrimitiveIncr" + x); 
     primitiveThreads.add(p); 
    } 

    boolean cont = true; 
    long atomicStart = System.currentTimeMillis(); 
    for(Thread t: atomicThreads){ 
     t.start(); 
    } 

    while(cont){ 
     try{ 
     Thread.sleep(whileSleep); 
     }catch(InterruptedException e){ 
     e.printStackTrace(); 
     } 

     boolean foundAlive = false; 
     for(Thread t: atomicThreads){ 
     foundAlive = (State.TERMINATED != t.getState()); 
     if(foundAlive){ 
      break; 
     } 
     } 

     cont = foundAlive; 

    } 

    long atomicFinish = System.currentTimeMillis(); 
    long atomicElapsed = atomicFinish - atomicStart; 
    long atomicFinal = atomic.getAtomicLong(); 

    cont = true; 
    long primitiveStart = System.currentTimeMillis(); 
    for(Thread t: primitiveThreads){ 
     t.start(); 
    } 

    while(cont){ 
     try{ 
     Thread.sleep(whileSleep); 
     }catch(InterruptedException e){ 
     e.printStackTrace(); 
     } 

     boolean foundAlive = false; 
     for(Thread t: primitiveThreads){ 
     foundAlive = (State.TERMINATED != t.getState()); 
     if(foundAlive){ 
      break; 
     } 
     } 

     cont = foundAlive; 
    long primitiveFinish = System.currentTimeMillis(); 
    long primitiveElapsed = primitiveFinish - primitiveStart; 
    long primitiveFinal = primitive.getPrimitiveLong(); 

    System.out.println(String.format(template, "ATOMIC", atomicElapsed, expectedValue, atomicFinal, (expectedValue==atomicFinal))); 
    System.out.println(String.format(template, "PrImItIvE", primitiveElapsed, expectedValue, primitiveFinal, (expectedValue==primitiveFinal))); 
    } 

IncrementAtomicRunnable:

public class IncrementAtomicRunnable implements Runnable{ 
    protected LongOverhead oh; 
    protected int loopTotal; 
    protected int waitMilliseconds; 
    protected String currentThreadName; 

    public IncrementAtomicRunnable(LongOverhead oh, int loopTotal, int waitMilliseconds){ 
    this.oh = oh; 
    this.loopTotal = loopTotal; 
    this.waitMilliseconds = waitMilliseconds; 
    } 

    @Override 
    public void run(){ 
    currentThreadName = Thread.currentThread().getName(); 
    System.out.println(currentThreadName + " for ATOMIC is starting....."); 
    for(int x=0;x<loopTotal;x++){ 
     oh.incrAtomicLong(); 
     try{ 
     Thread.sleep(waitMilliseconds); 
     }catch(InterruptedException e){ 
     System.out.println("InterruptedThread[" + currentThreadName + "], eating exception @@@@@"); 
     } 
    } 

    System.out.println("....." + currentThreadName + " for ATOMIC is finished."); 
    } 
} 

và cuối cùng IncrementPrimitiveRunnable:

public class IncrementPrimitiveRunnable extends IncrementAtomicRunnable{ 
    public IncrmentPrimitiveRunnable(LongOverhead oh, int loopTotal, int waitMilliseconds){ 
    super(oh, loopTotal, waitMilliseconds); 
    } 

    @Override 
    public void run(){ 
    super.currentThreadName = Thread.currentThread().getName(); 
    System.out.println(currentThreadName + " for PRIMITIVE is starting....."); 
    for(int x=0;x<loopTotal;x++){ 
     oh.incrPrimitiveLong(); 
     try{ 
     Thread.sleep(waitMilliseconds); 
     }catch(InterruptedException e){ 
     System.out.println("InterruptedThread[" + currentThreadName + "], eating exception @@@@@"); 
     } 
    } 

    System.out.println("....." + currentThreadName + " for PRIMITIVE is finished."); 
    } 
} 
Các vấn đề liên quan