Tôi đang đọc đa luồng trong Java và tôi bắt gặp điều này
Các biến cục bộ là chuỗi an toàn trong Java.
Kể từ đó tôi đã suy nghĩ Làm thế nào / Tại sao các biến cục bộ lại an toàn cho luồng.
Ai đó có thể vui lòng cho tôi biết.
Tôi đang đọc đa luồng trong Java và tôi bắt gặp điều này
Các biến cục bộ là chuỗi an toàn trong Java.
Kể từ đó tôi đã suy nghĩ Làm thế nào / Tại sao các biến cục bộ lại an toàn cho luồng.
Ai đó có thể vui lòng cho tôi biết.
Câu trả lời:
Khi bạn tạo một luồng, nó sẽ có ngăn xếp của riêng nó được tạo. Hai luồng sẽ có hai ngăn xếp và một luồng không bao giờ chia sẻ ngăn xếp của nó với luồng khác.
Tất cả các biến cục bộ được xác định trong chương trình của bạn sẽ được cấp phát bộ nhớ trong ngăn xếp (Như Jatin đã nhận xét, bộ nhớ ở đây có nghĩa là, giá trị tham chiếu cho các đối tượng và giá trị cho các kiểu nguyên thủy) (Mỗi lệnh gọi phương thức bởi một luồng tạo ra một khung ngăn xếp trên ngăn xếp của chính nó). Ngay sau khi quá trình thực thi phương thức được hoàn thành bởi luồng này, khung ngăn xếp sẽ bị xóa.
Có một bài giảng tuyệt vời của giáo sư Stanford trên youtube có thể giúp bạn hiểu khái niệm này.
Các biến cục bộ được lưu trữ trong ngăn xếp riêng của mỗi luồng. Điều đó có nghĩa là các biến cục bộ không bao giờ được chia sẻ giữa các luồng. Điều đó cũng có nghĩa là tất cả các biến nguyên thủy cục bộ đều an toàn.
public void someMethod(){
long threadSafeInt = 0;
threadSafeInt++;
}
Các tham chiếu cục bộ đến các đối tượng hơi khác một chút. Bản thân tham chiếu không được chia sẻ. Tuy nhiên, đối tượng được tham chiếu không được lưu trữ trong ngăn xếp cục bộ của mỗi luồng. Tất cả các đối tượng được lưu trữ trong heap được chia sẻ. Nếu một đối tượng được tạo cục bộ không bao giờ thoát khỏi phương thức mà nó đã được tạo trong đó, nó là luồng an toàn. Trên thực tế, bạn cũng có thể truyền nó cho các phương thức và đối tượng khác miễn là không có phương thức hoặc đối tượng nào trong số này làm cho đối tượng được truyền sẵn có cho các luồng khác
Hãy nghĩ về các phương pháp như định nghĩa về chức năng. Khi hai luồng chạy cùng một phương thức, chúng không liên quan gì đến nhau. Mỗi người sẽ tạo phiên bản riêng của từng biến cục bộ và sẽ không thể tương tác với nhau theo bất kỳ cách nào.
Nếu các biến không phải là cục bộ (như các biến cá thể được định nghĩa bên ngoài một phương thức ở cấp lớp), thì chúng sẽ được gắn vào cá thể (không phải cho một lần chạy phương thức). Trong trường hợp này, hai luồng chạy cùng một phương thức đều thấy một biến và điều này không an toàn cho luồng.
Hãy xem xét hai trường hợp sau:
public class NotThreadsafe {
int x = 0;
public int incrementX() {
x++;
return x;
}
}
public class Threadsafe {
public int getTwoTimesTwo() {
int x = 1;
x++;
return x*x;
}
}
Trong lần đầu tiên, hai luồng chạy trên cùng một phiên bản của NotThreadsafe
sẽ thấy cùng một dấu x. Điều này có thể nguy hiểm, bởi vì các chủ đề đang cố gắng thay đổi x! Trong thứ hai, hai luồng chạy trên cùng một phiên bản của Threadsafe
sẽ thấy các biến hoàn toàn khác nhau và không thể ảnh hưởng lẫn nhau.
Mỗi lệnh gọi phương thức có các biến cục bộ của riêng nó và hiển nhiên, một lệnh gọi phương thức xảy ra trong một luồng duy nhất. Một biến chỉ được cập nhật bởi một luồng duy nhất vốn dĩ là một luồng an toàn.
Tuy nhiên , hãy theo dõi kỹ ý nghĩa chính xác của điều này: chỉ các bản ghi vào chính biến là an toàn luồng; gọi các phương thức trên đối tượng mà nó tham chiếu đến vốn dĩ không an toàn theo luồng . Tương tự với việc cập nhật trực tiếp các biến của đối tượng.
Ngoài những câu trả lời khác như của Nambari.
Tôi muốn chỉ ra rằng bạn có thể sử dụng một biến cục bộ trong một phương thức kiểu ẩn danh:
Phương thức này có thể được gọi trong các luồng khác có thể ảnh hưởng đến sự an toàn của luồng, vì vậy java buộc tất cả các biến cục bộ được sử dụng trong các kiểu không rõ ràng phải được khai báo là cuối cùng.
Hãy xem xét mã bất hợp pháp này:
public void nonCompilableMethod() {
int i=0;
for(int t=0; t<100; t++)
{
new Thread(new Runnable() {
public void run() {
i++; //compile error, i must be final:
//Cannot refer to a non-final variable i inside an
//inner class defined in a different method
}
}).start();
}
}
Nếu java đã cho phép điều này (như C # thực hiện thông qua "bao đóng"), thì một biến cục bộ sẽ không còn là luồng an toàn trong mọi trường hợp. Trong trường hợp này, giá trị của i
ở cuối tất cả các luồng không được đảm bảo 100
.
Chủ đề sẽ có ngăn xếp riêng của nó. Hai luồng sẽ có hai ngăn xếp và một luồng không bao giờ chia sẻ ngăn xếp của nó với luồng khác. Các biến cục bộ được lưu trữ trong ngăn xếp riêng của mỗi luồng. Điều đó có nghĩa là các biến cục bộ không bao giờ được chia sẻ giữa các luồng.
Về cơ bản có bốn loại lưu trữ trong java để lưu trữ thông tin và dữ liệu Lớp:
Vùng phương pháp, đống, ngăn xếp JAVA, PC
vì vậy vùng Phương thức và Heap được chia sẻ bởi tất cả các luồng nhưng mọi luồng đều có Ngăn xếp và PC JAVA của riêng nó và nó không được chia sẻ bởi bất kỳ Chủ đề nào khác.
Mỗi phương thức trong java là khung Stack. vì vậy, khi một phương thức được gọi bởi một luồng mà khung ngăn xếp được tải trên Ngăn xếp JAVA của nó. Tất cả các biến cục bộ có trong khung ngăn xếp đó và ngăn xếp toán hạng liên quan sẽ không được chia sẻ bởi những người khác. PC sẽ có thông tin về lệnh tiếp theo để thực thi trong mã byte của phương thức. vì vậy tất cả các biến cục bộ đều THREAD AN TOÀN.
@Weston cũng đã đưa ra câu trả lời tốt.
Chỉ các biến cục bộ được lưu trữ trên ngăn xếp luồng.
Biến cục bộ đó là primitive type
(ví dụ int, long ...) được lưu trữ trên thread stack
và kết quả là - chủ đề khác không có quyền truy cập vào nó.
Biến cục bộ là reference type
(kế thừa của Object
) chứa từ 2 phần - địa chỉ (được lưu trên thread stack
) và đối tượng (được lưu trên heap
)
class MyRunnable implements Runnable() {
public void run() {
method1();
}
void method1() {
int intPrimitive = 1;
method2();
}
void method2() {
MyObject1 myObject1 = new MyObject1();
}
}
class MyObject1 {
MyObject2 myObject2 = new MyObject2();
}
class MyObject2 {
MyObject3 myObject3 = MyObject3.shared;
}
class MyObject3 {
static MyObject3 shared = new MyObject3();
boolean b = false;
}