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 synchronized
từ khóa.
- Ý nghĩa của
synchronized
từ 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?
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 synchronized
từ khóa.
synchronized
từ khóa là gì?synchronized
?Câu trả lời:
Các synchronized
từ 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ó synchronized
từ khóa, chủ đề 1 của bạn có thể không thấy chủ đề thay đổi 2 được thực hiện foo
hoặ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.
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 ý: synchronized
chặ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
synchronized
, nhưng tính nhất quán của bộ nhớ bị bỏ qua.
Các synchronized
từ 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 Hashtable
là synchronized
, 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 synchronized
cấ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.
synchronized
có 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ù synchronized
các khối không cung cấp lợi ích.
Các synchronized
từ 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.
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.
Cú pháp thông minh synchronized
từ khóa lấy Object
tham 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.
Thêm synchronized
từ 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óa là this
(ví dụ phương thức) và 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ó static
từ khóa.
- Phương thức lớp là một phương thức có static
từ khóa.
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ó
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
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.
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 synchronized
và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:
Synchronized normal method
tươ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 method
tươ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 Methods
và Synchronized Statements
. Tuy nhiên, Synchronized Methods
tương tự như Synchronized Statements
vậ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
intrinsic lock
liên kết với nó.synchronized statement
, nó sẽ tự động lấy đối tượng intrinsic lock
đó synchronized statement's
và 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 A
gọ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 A
mở 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?)
Tôi thích synchronized statements
bở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
(nó không liên quan nhiều đến synchronized
nó, nó khác nhau giữa đối tượng và lớp hoặc không tĩnh và tĩnh).
synchronized
hoặ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. synchronized
hoặc phương thức tĩnh synchronized(class)
hoặc synchronized(static variable)
nó sẽ được đồng bộ hóa trên lớphttps://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
Đâ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
count
là một thể hiện củaSynchronizedCounter
, 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.
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ì).
Đ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.
Đồ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 đơ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()
synchronized
khối trong Java là một màn hình trong đa luồng. synchronized
khố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 condition
tì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 volatile
Giới thiệu )
Java 5
mở rộng synchronized
bằ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