"Đồng bộ hóa" nghĩa là gì?


993

Tôi có một số câu hỏi liên quan đến việc sử dụng và tầm quan trọng của synchronizedtừ khóa.

  • Ý nghĩa của synchronizedtừ khóa là gì?
  • Khi nào nên phương pháp synchronized?
  • Nó có nghĩa là gì về mặt lập trình và logic?


1
thảo luận hữu ích giữa hashmap và hashtable và đồng bộ hóa: stackoverflow.com/questions/40471/java-hashmap-vs-hashtable
limc


1
Tôi đã xem qua toàn bộ liên kết tài liệu từ bình luận đầu tiên và không hiểu cho đến khi tôi đi đến đoạn cuối cùng. Thay vì dán các liên kết và trích dẫn không có gì, có thể dán các liên kết và thêm một trích dẫn sẽ hữu ích hơn.
Rakib

Câu trả lời:


878

Các synchronizedtừ khóa là tất cả về chủ đề khác nhau đọc và viết vào các biến tương tự, các đối tượng và các nguồn lực. Đây không phải là một chủ đề tầm thường trong Java, nhưng đây là một trích dẫn từ Sun:

synchronized các phương thức cho phép một chiến lược đơn giản để ngăn chặn sự can thiệp của luồng và lỗi nhất quán bộ nhớ: nếu một đối tượng hiển thị với nhiều hơn một luồng, tất cả việc đọc hoặc ghi vào các biến của đối tượng đó được thực hiện thông qua các phương thức được đồng bộ hóa.

Tóm lại, rất nhỏ: Khi bạn có hai luồng đang đọc và ghi vào cùng một "tài nguyên", giả sử một biến có tên foo, bạn cần đảm bảo rằng các luồng này truy cập vào biến theo cách nguyên tử. Nếu không có synchronizedtừ khóa, chủ đề 1 của bạn có thể không thấy chủ đề thay đổi 2 được thực hiện foohoặc tệ hơn, nó chỉ có thể được thay đổi một nửa. Đây không phải là những gì bạn mong đợi một cách hợp lý.

Một lần nữa, đây là một chủ đề không tầm thường trong Java. Để tìm hiểu thêm, hãy khám phá các chủ đề ở đây trên SO và Interwebs về:

Tiếp tục khám phá những chủ đề này cho đến khi cái tên "Brian Goetz" trở thành vĩnh viễn gắn liền với thuật ngữ "đồng thời" trong não của bạn.


71
Vì vậy, về cơ bản từ khóa được Đồng bộ hóa này có làm cho phương thức của bạn an toàn không?
Rigo Vides

82
Từ khóa được đồng bộ hóa là một trong những công cụ giúp cho chuỗi mã của bạn an toàn. Chỉ sử dụng đồng bộ hóa trên một phương thức hoặc chính biến có thể hoặc không thể thực hiện thủ thuật. Có một sự hiểu biết cơ bản về Mô hình bộ nhớ Java là rất quan trọng để có được sự đồng thời chính xác.
Stu Thompson

28
Trừ khi bạn là Brian Goetz (hoặc có thể là Jon Skeet), gần như không thể có được sự tương tranh Java chính xác chỉ với các nguyên thủy ngôn ngữ (được đồng bộ hóa, không ổn định). Để bắt đầu, hãy sử dụng gói java.util.conc hiện và xây dựng trên đó.
Thilo

12
Rõ ràng hơn: các phương thức được đồng bộ hóa không thể được gọi cùng lúc từ nhiều luồng.
peterh - Phục hồi Monica

2
@peterh được đồng bộ hóa làm nhiều hơn thế, do đó giải thích dài dòng hơn
Stu Thompson

293

Chà, tôi nghĩ rằng chúng ta đã có đủ các giải thích lý thuyết, vì vậy hãy xem xét mã này

public class SOP {
    public static void print(String s) {
        System.out.println(s+"\n");
    }
}

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;
    public TestThread(String name,TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }
    @Override
    public void run() {
        theDemo.test(name);
    }
}

public class TheDemo {
    public synchronized void test(String name) {
        for(int i=0;i<10;i++) {
            SOP.print(name + " :: "+i);
            try{
                Thread.sleep(500);
            } catch (Exception e) {
                SOP.print(e.getMessage());
            }
        }
    }
    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1",theDemo);
        new TestThread("THREAD 2",theDemo);
        new TestThread("THREAD 3",theDemo);
    }
}

Lưu ý: synchronizedchặn cuộc gọi của luồng tiếp theo đến phương thức test () miễn là việc thực hiện luồng trước đó chưa kết thúc. Chủ đề có thể truy cập phương pháp này một lần. Không cósynchronized tất cả các chủ đề có thể truy cập phương pháp này đồng thời.

Khi một luồng gọi phương thức được đồng bộ hóa 'test' của đối tượng (ở đây đối tượng là một thể hiện của lớp 'TheDemo'), nó thu được khóa của đối tượng đó, bất kỳ luồng mới nào cũng không thể gọi phương thức được đồng bộ hóa của cùng một đối tượng miễn là luồng trước đó mà đã có được khóa không phát hành khóa.

Điều tương tự xảy ra khi bất kỳ phương thức đồng bộ tĩnh nào của lớp được gọi. Luồng có được khóa được liên kết với lớp (trong trường hợp này, bất kỳ phương thức không đồng bộ tĩnh nào của một thể hiện của lớp đó có thể được gọi bởi bất kỳ luồng nào vì khóa cấp đối tượng đó vẫn khả dụng). Bất kỳ luồng nào khác sẽ không thể gọi bất kỳ phương thức đồng bộ tĩnh nào của lớp miễn là khóa cấp độ lớp không được giải phóng bởi luồng hiện đang giữ khóa.

Đầu ra được đồng bộ hóa

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

Đầu ra không đồng bộ

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9

7
Ví dụ tuyệt vời, thật tốt khi biết lý thuyết, nhưng mã luôn cụ thể và đầy đủ hơn.
Santi Iglesias

2
@SantiIglesias "Hoàn thành"? Không. Ví dụ này cho thấy hành vi khóa của synchronized, nhưng tính nhất quán của bộ nhớ bị bỏ qua.
Stu Thompson

2
Tính nhất quán của bộ nhớ @Stu Thompson là kết quả của việc khóa
Dheeraj Sachan

@DheerajSachan Theo logic đó, sau đó sử dụng ReentrantLock sẽ dẫn đến tính nhất quán của bộ nhớ. Nó không.
Stu Thompson

3
@boltup_im_coding: Phương thức start () đặt Thread ở trạng thái "RUNNABLE", nghĩa là nó đã sẵn sàng để thực thi hoặc đã thực thi. Có thể xảy ra việc một luồng khác (thường nhưng không nhất thiết phải có mức ưu tiên cao hơn) trong trạng thái Runnable nhảy hàng đợi và bắt đầu thực thi. Trong ví dụ trên, THREAD 3 đã tình cờ nhận được CPU trước THREAD 2.
Sahil J

116

Các synchronizedtừ khóa ngăn chặn truy cập đồng thời vào một khối mã hoặc đối tượng bằng nhiều chủ đề. Tất cả các phương thức Hashtablesynchronized, vì vậy chỉ có một luồng có thể thực thi bất kỳ trong số chúng tại một thời điểm.

Khi sử dụng các synchronizedcấu trúc không như cấu trúc HashMap, bạn phải xây dựng các tính năng an toàn luồng trong mã của mình để ngăn ngừa lỗi thống nhất.


81

synchronizedcó nghĩa là trong một môi trường đa luồng, một đối tượng có synchronized(các) phương thức / khối (s) không cho phép hai luồng truy cập vàosynchronized (các) phương thức / khối (các) mã cùng một lúc. Điều này có nghĩa là một luồng không thể đọc trong khi một luồng khác cập nhật nó.

Thay vào đó, luồng thứ hai sẽ đợi cho đến khi luồng đầu tiên hoàn thành việc thực hiện. Chi phí hoạt động là tốc độ, nhưng lợi thế là đảm bảo tính nhất quán của dữ liệu.

Nếu ứng dụng của bạn là một luồng đơn, mặc dù synchronizedcác khối không cung cấp lợi ích.


54

Các synchronizedtừ khóa gây ra một chủ đề để có được một khóa khi nhập phương pháp này, vì vậy mà chỉ có một thread có thể thực hiện phương pháp này đồng thời (đối với trường hợp đối tượng nhất định, trừ khi nó là một phương pháp tĩnh).

Điều này thường được gọi là làm cho chủ đề lớp an toàn, nhưng tôi sẽ nói đây là một uyển ngữ. Mặc dù đúng là đồng bộ hóa bảo vệ trạng thái bên trong của Vector khỏi bị hỏng, nhưng điều này thường không giúp người dùng Vector nhiều.

Xem xét điều này:

 if (vector.isEmpty()){
     vector.add(data);
 }

Mặc dù các phương thức liên quan được đồng bộ hóa, bởi vì chúng đang bị khóa và mở khóa riêng lẻ, hai luồng không may có thời gian có thể tạo ra một vectơ với hai phần tử.

Vì vậy, trong thực tế, bạn phải đồng bộ hóa trong mã ứng dụng của bạn.

Bởi vì đồng bộ hóa ở mức phương thức là một) tốn kém khi bạn không cần nó và b) không đủ khi bạn cần đồng bộ hóa, giờ đây đã có các thay thế không được đồng bộ hóa (ArrayList trong trường hợp Vector).

Gần đây, gói tương tranh đã được phát hành, với một số tiện ích thông minh xử lý các vấn đề đa luồng.


26

Tổng quat

Từ khóa được đồng bộ hóa trong Java phải thực hiện với an toàn luồng, nghĩa là khi nhiều luồng đọc hoặc ghi cùng một biến.
Điều này có thể xảy ra trực tiếp (bằng cách truy cập cùng một biến) hoặc gián tiếp (bằng cách sử dụng một lớp sử dụng một lớp khác truy cập cùng một biến).

Từ khóa được đồng bộ hóa được sử dụng để xác định một khối mã trong đó nhiều luồng có thể truy cập cùng một biến theo cách an toàn.

Sâu sắc hơn

Cú pháp thông minh synchronizedtừ khóa lấy Objecttham số làm tham số (được gọi là đối tượng khóa ), sau đó được theo sau bởi a { block of code }.

  • Khi thực thi gặp từ khóa này, luồng hiện tại cố gắng "khóa / thu / sở hữu" (chọn lựa) đối tượng khóa và thực thi khối mã liên quan sau khi khóa được lấy.

  • Bất kỳ ghi vào biến nào trong khối mã được đồng bộ hóa đều được đảm bảo hiển thị cho mọi luồng khác thực thi mã tương tự bên trong khối mã được đồng bộ hóa bằng cùng một đối tượng khóa .

  • Chỉ một luồng tại một thời điểm có thể giữ khóa, trong thời gian đó, tất cả các luồng khác cố gắng thu được cùng một đối tượng khóa sẽ chờ (tạm dừng thực thi của chúng). Khóa sẽ được giải phóng khi thực thi thoát khỏi khối mã được đồng bộ hóa.

Phương pháp đồng bộ hóa:

Thêm synchronizedtừ khóa vào một định nghĩa phương thức bằng với toàn bộ thân phương thức được gói trong một khối mã được đồng bộ hóa với đối tượng khóathis (ví dụ phương thức)ClassInQuestion.getClass() (đối với phương thức lớp) .

- Phương pháp sơ thẩm là một phương pháp không có statictừ khóa.
- Phương thức lớp là một phương thức có statictừ khóa.

Kỹ thuật

Nếu không đồng bộ hóa, nó không được đảm bảo theo thứ tự đọc và ghi xảy ra, có thể để lại biến với rác.
(Ví dụ, một biến có thể kết thúc bằng một nửa số bit được viết bởi một luồng và một nửa số bit được viết bởi một luồng khác, để biến đó ở trạng thái mà cả hai luồng đều không cố ghi, nhưng là một mớ hỗn độn của cả hai.)

Không đủ để hoàn thành một thao tác ghi trong một luồng trước đó (thời gian đồng hồ treo tường) một luồng khác đọc nó, bởi vì phần cứng có thể lưu trữ giá trị của biến và luồng đọc sẽ thấy giá trị được lưu trong bộ nhớ cache thay vì được ghi vào nó

Phần kết luận

Do đó, trong trường hợp của Java, bạn phải tuân theo Mô hình bộ nhớ Java để đảm bảo rằng các lỗi luồng không xảy ra.
Nói cách khác: Sử dụng đồng bộ hóa, hoạt động nguyên tử hoặc các lớp sử dụng chúng cho bạn dưới mui xe.

Nguồn

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
Đặc tả ngôn ngữ Java®, 2015/02/13


Xin lỗi, nhưng tôi có ví dụ này và tôi không hiểu ý nghĩa: `Integer i1 = Arrays.asList (1,2,3,4,5) .stream (). FindAny (). Get (); đã đồng bộ hóa (i1) {Integer i2 = Arrays.asList (6,7,8,9,10). ChampionsStream () .sort () .findAny (). get (); System.out.println (i1 + "" + i2); } `1. Tại sao bạn gọi khối trong trường hợp đầu tiên và lời gọi này không ảnh hưởng đến mã? 2. Ví dụ thứ hai sẽ an toàn cho luồng, bất chấp lệnh gọi khối trên đầu tiên?
Adryr83

1
@ Adryr83 Nếu bạn có một câu hỏi, có lẽ bạn có thể hỏi nó bằng cách đăng một câu hỏi mới. Nhưng vì chúng tôi ở đây, tôi sẽ phân tích những gì tôi có thể (câu hỏi của bạn hơi khó hiểu). Từ những gì tôi có thể nói về đoạn mã đó, dường như không chứa bất cứ thứ gì đòi hỏi phải đồng bộ hóa. Nó nằm ngoài bối cảnh. Gợi ý: Nếu bạn có thể, hãy thử chia mã thành từng phần nhỏ hơn, sau đó tìm kiếm câu trả lời về những điều đó. Việc cố gắng hiểu các vấn đề nhỏ và biệt lập sẽ dễ dàng hơn nhiều so với cố gắng tìm ra một khối mã lớn.
Gima

21

Hãy nghĩ về nó như một loại cửa quay như bạn có thể tìm thấy ở một sân bóng đá. Có những hơi nước song song của những người muốn vào nhưng ở cửa quay, họ được 'đồng bộ hóa'. Chỉ một người tại một thời điểm có thể vượt qua. Tất cả những người muốn vượt qua sẽ làm, nhưng họ có thể phải đợi cho đến khi họ có thể đi qua.


16

Từ khóa được đồng bộ hóa là gì?

Chủ đề giao tiếp chủ yếu bằng cách chia sẻ quyền truy cập vào các trường và các trường tham chiếu đối tượng tham chiếu. Hình thức giao tiếp này cực kỳ hiệu quả, nhưng làm cho hai loại lỗi có thể xảy ra: nhiễu luồng và lỗi nhất quán bộ nhớ . Công cụ cần thiết để ngăn chặn các lỗi này là đồng bộ hóa.

Các khối hoặc phương thức được đồng bộ hóa ngăn chặn nhiễu luồng và đảm bảo dữ liệu phù hợp. Tại bất kỳ thời điểm nào, chỉ một luồng có thể truy cập vào một khối hoặc phương thức được đồng bộ hóa ( phần quan trọng ) bằng cách có được một khóa. Các luồng khác sẽ chờ phát hành khóa để truy cập phần quan trọng .

Khi nào các phương thức được đồng bộ hóa?

Các phương thức được đồng bộ hóa khi bạn thêm synchronizedvào định nghĩa hoặc khai báo phương thức. Bạn cũng có thể đồng bộ hóa một khối mã cụ thể với một phương thức.

Nó có nghĩa là pro ngữ pháp và logic?

Nó có nghĩa là chỉ một chủ đề có thể truy cập vào phần quan trọng bằng cách có được một khóa. Trừ khi chủ đề này giải phóng khóa này, tất cả (các) chủ đề khác sẽ phải chờ để có được khóa. Họ không có quyền truy cập để vào phần quan trọng mà không cần khóa.

Điều này không thể được thực hiện với một phép thuật. Lập trình viên có trách nhiệm xác định (các) phần quan trọng trong ứng dụng và bảo vệ nó cho phù hợp. Java cung cấp một khung để bảo vệ ứng dụng của bạn, nhưng nơi và tất cả các phần cần bảo vệ là trách nhiệm của lập trình viên.

Thêm chi tiết từ trang tài liệu java

Khóa nội bộ và đồng bộ hóa:

Đồng bộ hóa được xây dựng xung quanh một thực thể nội bộ được gọi là khóa nội tại hoặc khóa màn hình. Khóa nội tại đóng một vai trò trong cả hai khía cạnh của đồng bộ hóa: thực thi quyền truy cập độc quyền vào trạng thái của đối tượng và thiết lập xảy ra - trước các mối quan hệ thiết yếu đối với khả năng hiển thị.

Mỗi đối tượng có một khóa nội tại liên quan đến nó . Theo quy ước, một luồng cần truy cập độc quyền và nhất quán vào các trường của đối tượng phải có được khóa nội tại của đối tượng trước khi truy cập vào chúng, sau đó giải phóng khóa nội tại khi thực hiện với chúng.

Một chủ đề được cho là sở hữu khóa nội tại giữa thời gian nó có được khóa và phát hành khóa. Miễn là một luồng sở hữu một khóa nội tại, không có luồng nào khác có thể có được cùng một khóa. Các luồng khác sẽ chặn khi nó cố gắng để có được khóa.

Khi một luồng giải phóng một khóa nội tại, một mối quan hệ xảy ra trước khi được thiết lập giữa hành động đó và bất kỳ việc mua lại cùng một khóa.

Làm cho các phương thức được đồng bộ hóa có hai tác dụng :

Đầu tiên, không thể có hai yêu cầu của các phương thức được đồng bộ hóa trên cùng một đối tượng để xen kẽ.

Khi một luồng đang thực thi một phương thức được đồng bộ hóa cho một đối tượng, tất cả các luồng khác gọi các phương thức được đồng bộ hóa cho cùng một khối đối tượng (tạm dừng thực thi) cho đến khi luồng đầu tiên được thực hiện với đối tượng.

Thứ hai, khi một phương thức được đồng bộ hóa thoát ra, nó sẽ tự động thiết lập mối quan hệ xảy ra trước khi có bất kỳ lời gọi tiếp theo nào của một phương thức được đồng bộ hóa cho cùng một đối tượng.

Điều này đảm bảo rằng những thay đổi về trạng thái của đối tượng được hiển thị cho tất cả các luồng.

Tìm kiếm các lựa chọn thay thế khác để đồng bộ hóa trong:

Tránh đồng bộ hóa (cái này) trong Java?


11

Synchronized normal methodtương đương với Synchronized statement(sử dụng cái này)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized static methodtương đương với Synchronized statement(lớp sử dụng)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

Câu lệnh được đồng bộ hóa (sử dụng biến)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

Đối với synchronized, chúng tôi có cả Synchronized MethodsSynchronized Statements. Tuy nhiên, Synchronized Methodstương tự như Synchronized Statementsvậy nên chúng ta chỉ cần hiểuSynchronized Statements .

=> Về cơ bản, chúng ta sẽ có

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

Đây là 2 suy nghĩ giúp hiểu synchronized

  • Mỗi đối tượng / lớp có một intrinsic lockliên kết với nó.
  • Khi một luồng gọi a synchronized statement, nó sẽ tự động lấy đối tượng intrinsic lockđó synchronized statement'svà giải phóng nó khi phương thức trả về. Miễn là một luồng sở hữu một intrinsic lock, KHÔNG có luồng nào khác có thể có được khóa SAME => luồng an toàn.

=> Khi một lệnh thread Agọi synchronized(this){// code 1}=> tất cả mã khối (bên trong lớp) trong đó có synchronized(this)và tất cả synchronized normal method(bên trong lớp) bị khóa vì khóa CÙNG . Nó sẽ thực thi sau khi thread Amở khóa ("// mã 1" kết thúc).

Hành vi này tương tự synchronized(a variable){// code 1}hoặc synchronized(class).

CÙNG LOCK => khóa (không phụ thuộc vào phương thức nào? Hoặc câu lệnh nào?)

Sử dụng phương pháp đồng bộ hay báo cáo đồng bộ?

Tôi thích synchronized statementsbởi vì nó là mở rộng hơn. Ví dụ, trong tương lai, bạn chỉ cần đồng bộ hóa một phần của phương thức. Ví dụ, bạn có 2 phương thức được đồng bộ hóa và nó không có bất kỳ phương thức nào có liên quan với nhau, tuy nhiên khi một luồng chạy một phương thức, nó sẽ chặn phương thức khác (nó có thể ngăn chặn bằng cách sử dụng synchronized(a variable)).

Tuy nhiên, áp dụng phương thức đồng bộ là đơn giản và mã trông đơn giản. Đối với một số lớp, chỉ có 1 phương thức được đồng bộ hóa hoặc tất cả các phương thức được đồng bộ hóa trong lớp có liên quan với nhau => chúng ta có thể sử dụng synchronized methodđể làm cho mã ngắn hơn và dễ hiểu

Ghi chú

(nó không liên quan nhiều đến synchronizednó, nó khác nhau giữa đối tượng và lớp hoặc không tĩnh và tĩnh).

  • Khi bạn sử dụng synchronizedhoặc phương thức bình thường synchronized(this)hoặc synchronized(non-static variable)nó sẽ được đồng bộ hóa trên từng đối tượng.
  • Khi bạn sử dụng synchronizedhoặc phương thức tĩnh synchronized(class)hoặc synchronized(static variable)nó sẽ được đồng bộ hóa trên lớp

Tài liệu tham khảo

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

Hy vọng nó sẽ giúp


11

Đây là một lời giải thích từ Hướng dẫn Java .

Hãy xem xét các mã sau đây:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

nếu countlà một thể hiện của SynchronizedCounter, thì làm cho các phương thức này được đồng bộ hóa có hai hiệu ứng:

  • Đầu tiên, không thể có hai yêu cầu của các phương thức được đồng bộ hóa trên cùng một đối tượng để xen kẽ. Khi một luồng đang thực thi một phương thức được đồng bộ hóa cho một đối tượng, tất cả các luồng khác gọi các phương thức được đồng bộ hóa cho cùng một khối đối tượng (tạm dừng thực thi) cho đến khi luồng đầu tiên được thực hiện với đối tượng.
  • Thứ hai, khi một phương thức được đồng bộ hóa thoát ra, nó sẽ tự động thiết lập mối quan hệ xảy ra trước khi có bất kỳ lời gọi tiếp theo nào của một phương thức được đồng bộ hóa cho cùng một đối tượng. Điều này đảm bảo rằng những thay đổi về trạng thái của đối tượng được hiển thị cho tất cả các luồng.

9

Theo hiểu biết của tôi về cơ bản được đồng bộ hóa có nghĩa là trình biên dịch viết một Monitor.enter và Monitor.exit xung quanh phương thức của bạn. Vì vậy, nó có thể là luồng an toàn tùy thuộc vào cách sử dụng nó (ý tôi là bạn có thể viết một đối tượng với các phương thức được đồng bộ hóa không phải là luồng an toàn tùy thuộc vào lớp của bạn làm gì).


5

Điều mà các câu trả lời khác còn thiếu là một khía cạnh quan trọng: rào cản bộ nhớ . Đồng bộ hóa chủ đề bao gồm hai phần: tuần tự hóa và khả năng hiển thị. Tôi khuyên mọi người nên google cho "hàng rào bộ nhớ jvm", vì đây là một chủ đề không tầm thường và cực kỳ quan trọng (nếu bạn sửa đổi dữ liệu chia sẻ được truy cập bởi nhiều luồng). Đã làm điều đó, tôi khuyên bạn nên xem các lớp của gói java.util.conc hiện giúp tránh sử dụng đồng bộ hóa rõ ràng, từ đó giúp giữ cho các chương trình đơn giản và hiệu quả, thậm chí có thể ngăn chặn các bế tắc.

Một ví dụ như vậy là ConcurrencyLinkedDeque . Cùng với mẫu lệnh, nó cho phép tạo các luồng công nhân hiệu quả cao bằng cách nhồi các lệnh vào hàng đợi đồng thời - không cần đồng bộ hóa rõ ràng, không có bế tắc, không cần ngủ rõ ràng (), chỉ cần thăm dò hàng đợi bằng cách gọi Take ().

Tóm lại: "đồng bộ hóa bộ nhớ" xảy ra ngầm khi bạn bắt đầu một luồng, một luồng kết thúc, bạn đọc một biến dễ bay hơi, bạn mở khóa màn hình (để lại một khối / chức năng được đồng bộ hóa), v.v. ") Tất cả các văn bản được thực hiện trước hành động cụ thể đó. Trong trường hợp nói trên ConcurrentLinkedDeque , tài liệu "nói":

Hiệu ứng nhất quán của bộ nhớ: Cũng như các bộ sưu tập đồng thời khác, các hành động trong một luồng trước khi đặt một đối tượng vào một hành động đồng thời xảy ra trước khi truy cập hoặc loại bỏ phần tử đó khỏi ConcurrencyLinkedDeque trong một luồng khác.

Hành vi ngầm này là một khía cạnh nguy hiểm vì hầu hết các lập trình viên Java không có nhiều kinh nghiệm sẽ chỉ mất nhiều thời gian vì nó. Và sau đó đột nhiên vấp phải luồng này sau khi Java không thực hiện những gì được cho là "phải làm" trong sản xuất khi có khối lượng công việc khác nhau - và thật khó để kiểm tra các vấn đề tương tranh.


3

Đồng bộ hóa đơn giản có nghĩa là nhiều luồng nếu được liên kết với một đối tượng có thể ngăn chặn việc đọc và ghi bẩn nếu khối được đồng bộ hóa được sử dụng trên đối tượng cụ thể. Để cho bạn rõ ràng hơn, hãy lấy một ví dụ:

class MyRunnable implements Runnable {
    int var = 10;
    @Override
    public void run() {
        call();
    }

    public void call() {
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                var++;
                System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var);
            }
        }
    }
}

public class MutlipleThreadsRunnable {
    public static void main(String[] args) {
        MyRunnable runnable1 = new MyRunnable();
        MyRunnable runnable2 = new MyRunnable();
        Thread t1 = new Thread(runnable1);
        t1.setName("Thread -1");
        Thread t2 = new Thread(runnable2);
        t2.setName("Thread -2");
        Thread t3 = new Thread(runnable1);
        t3.setName("Thread -3");
        t1.start();
        t2.start();
        t3.start();
    }
}

Chúng tôi đã tạo hai đối tượng lớp MyRunnable, runnable1 được chia sẻ với luồng 1 và luồng 3 & runnable2 chỉ được chia sẻ với luồng 2. Bây giờ khi t1 và t3 bắt đầu mà không được sử dụng đồng bộ hóa, đầu ra PFB cho thấy cả hai luồng 1 và 3 đồng thời ảnh hưởng đến giá trị var trong đó đối với luồng 2, var có bộ nhớ riêng.

Without Synchronized keyword

    Current Thread Thread -1 var value 11
    Current Thread Thread -2 var value 11
    Current Thread Thread -2 var value 12
    Current Thread Thread -2 var value 13
    Current Thread Thread -2 var value 14
    Current Thread Thread -1 var value 12
    Current Thread Thread -3 var value 13
    Current Thread Thread -3 var value 15
    Current Thread Thread -1 var value 14
    Current Thread Thread -1 var value 17
    Current Thread Thread -3 var value 16
    Current Thread Thread -3 var value 18

Sử dụng Đồng bộ hóa, luồng 3 chờ luồng 1 hoàn thành trong tất cả các tình huống. Có hai khóa thu được, một khóa trên runnable1 được chia sẻ bởi luồng 1 và luồng 3 và một khóa khác trên runnable2 chỉ được chia sẻ bởi luồng 2.

Current Thread Thread -1 var value 11
Current Thread Thread -2 var value 11
Current Thread Thread -1 var value 12
Current Thread Thread -2 var value 12
Current Thread Thread -1 var value 13
Current Thread Thread -2 var value 13
Current Thread Thread -1 var value 14
Current Thread Thread -2 var value 14
Current Thread Thread -3 var value 15
Current Thread Thread -3 var value 16
Current Thread Thread -3 var value 17
Current Thread Thread -3 var value 18

Đồng bộ hóa có nghĩa là nhiều hơn thế: nó có tác động sâu sắc đến hàng rào bộ nhớ.
dùng1050755

1

đồng bộ hóa đơn giản có nghĩa là không có hai luồng có thể truy cập đồng thời khối / phương thức. Khi chúng ta nói bất kỳ khối / phương thức nào của một lớp được đồng bộ hóa, điều đó có nghĩa là chỉ một luồng có thể truy cập chúng tại một thời điểm. Bên trong luồng cố gắng truy cập nó trước tiên sẽ khóa một đối tượng đó và miễn là khóa này không có sẵn thì không có luồng nào khác có thể truy cập bất kỳ phương thức / khối được đồng bộ hóa nào của thể hiện của lớp đó.

Lưu ý một luồng khác có thể truy cập một phương thức của cùng một đối tượng không được xác định là được đồng bộ hóa. Một chủ đề có thể giải phóng khóa bằng cách gọi

Object.wait()

0

synchronizedkhối trong Java là một màn hình trong đa luồng. synchronizedkhối với cùng một đối tượng / lớp có thể được thực thi chỉ bằng một luồng duy nhất, tất cả các khối khác đang chờ. Nó có thể giúp giải quyết race conditiontình huống khi một số luồng cố gắng cập nhật cùng một biến (bước đầu tiên là sử dụng volatileGiới thiệu )

Java 5mở rộng synchronizedbằng cách hỗ trợ happens-before[Giới thiệu]

Việc mở khóa (khối được đồng bộ hóa hoặc thoát phương thức) của một màn hình xảy ra - trước mỗi lần khóa tiếp theo (khối được đồng bộ hóa hoặc nhập phương thức) của cùng một màn hình đó.

Bước tiếp theo là java.util.concurrent

dễ bay hơi so với đồng bộ


-6

được đồng bộ hóa là một từ khóa trong Java, được sử dụng để thực hiện trước khi quan hệ trong môi trường đa luồng để tránh sự không nhất quán bộ nhớ và lỗi nhiễu luồng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.