2009-09-01 35 views
86

Tôi có một chức năng sử dụng Pattern.compile và một Matcher để tìm kiếm một danh sách các chuỗi cho một mẫu. Hàm này được sử dụng trong nhiều luồng. Mỗi chuỗi sẽ có một mẫu duy nhất được chuyển tới Pattern.compile khi chuỗi được tạo. Số lượng các chủ đề và các mẫu là năng động, có nghĩa là tôi có thể thêm nhiều mẫu và chủ đề hơn trong quá trình cấu hình.Chủ đề Java Regex có an toàn không?

Tôi có cần phải "đồng bộ hóa" chức năng này nếu nó sử dụng regex không? Là regex trong thread java an toàn?

TIA

Trả lời

108

, từ các tài liệu Java API cho Instances Pattern class

của (Pattern) này lớp là không thay đổi và được an toàn để sử dụng bởi nhiều luồng đồng thời. Các cá thể của lớp Matcher không an toàn cho việc sử dụng đó.

Nếu bạn đang xem mã trung tâm hiệu suất, hãy thử đặt lại cá thể Matcher bằng phương thức reset(), thay vì tạo phiên bản mới. Điều này sẽ thiết lập lại trạng thái của cá thể Matcher, làm cho nó có thể sử dụng cho hoạt động regex tiếp theo. Trong thực tế, nó là trạng thái được duy trì trong cá thể Matcher có trách nhiệm không an toàn cho việc truy cập đồng thời.

+15

Đối tượng mẫu là chủ đề an toàn, nhưng phương thức 'biên dịch()' có thể không.Đã có hai hoặc ba lỗi trong những năm gây ra sự biên dịch thất bại trong môi trường đa luồng. Tôi sẽ khuyên bạn nên làm việc biên dịch trong một khối đồng bộ. –

+2

Có, đã xảy ra lỗi đồng thời trong lớp Mẫu và lời khuyên của bạn về truy cập được đồng bộ hóa được đánh giá cao. Tuy nhiên, các nhà phát triển ban đầu của lớp Pattern nhằm làm cho lớp Pattern là thread an toàn, và đó là hợp đồng mà bất kỳ lập trình viên Java nào cũng có thể dựa vào. Thành thật mà nói, tôi muốn có các biến địa phương luồng và chấp nhận hiệu suất tối thiểu hơn là dựa vào hành vi an toàn của luồng theo hợp đồng (trừ khi tôi đã nhìn thấy mã). Khi họ nói "Threading là dễ dàng, đồng bộ hóa chính xác là khó". –

+1

Lưu ý rằng nguồn của "Mẫu" nằm trong bản phân phối JDK của Oracle (Theo http://www.oracle.com/technetwork/java/faq-141681.html#A14: "SDK Java 2, bản Standard Edition chứa một tệp có tên là src.zip có chứa mã nguồn cho các lớp công khai trong gói java ") để người dùng có thể tự mình xem nhanh. –

3

Mặc dù bạn cần phải nhớ rằng an toàn luồng cũng phải tính đến mã xung quanh, bạn dường như đang gặp may. Thực tế là Matchers được tạo bằng phương pháp nhà máy của matcher và thiếu nhà thầu công khai là một dấu hiệu tích cực. Tương tự, bạn sử dụng phương thức tĩnh compile để tạo bao gồm Pattern.

Vì vậy, trong ngắn hạn, nếu bạn làm điều gì đó như ví dụ:

Pattern p = Pattern.compile("a*b"); 
Matcher m = p.matcher("aaaaab"); 
boolean b = m.matches(); 

bạn nên làm khá tốt.

Theo dõi ví dụ mã để rõ ràng: lưu ý rằng ví dụ này ngụ ý rõ ràng rằng Trình tạo phù hợp được tạo ra là chuỗi cục bộ với Mẫu và thử nghiệm. Tức là, bạn không nên để lộ Matcher do đó tạo ra cho bất kỳ chủ đề khác.

Thành thật mà nói, đó là rủi ro của bất kỳ câu hỏi an toàn chủ đề nào. Thực tế là bất kỳ mã nào có thể được tạo thành chuỗi không an toàn nếu bạn cố gắng hết sức. May mắn thay, có wonderfulbooks dạy cho chúng tôi một loạt các cách mà chúng tôi có thể làm hỏng mã của chúng tôi. Nếu chúng ta tránh xa những sai lầm đó, chúng ta sẽ giảm đáng kể khả năng của chúng ta về vấn đề luồng.

+0

điều này phải làm gì với an toàn luồng? –

+0

@ Jason S: địa phương chủ đề là một cách rất đơn giản để đạt được an toàn luồng ngay cả khi mã nội bộ không phải là luồng an toàn. Nếu chỉ có một phương pháp có thể bao giờ có thể truy cập một phương thức cụ thể tại một thời điểm, bạn đã thực thi an toàn luồng bên ngoài. –

+1

ok, vì vậy bạn chỉ đang nói rằng tái tạo một mẫu từ một chuỗi tại điểm sử dụng, tốt hơn là lưu trữ nó để có hiệu quả, có nguy cơ đối phó với các vấn đề đồng thời không? Tôi sẽ cấp cho bạn điều đó. Tôi đã nhầm lẫn với câu đó về phương pháp nhà máy và nhà thầu công cộng, điều đó có vẻ giống như một cá trích đỏ w/r/t chủ đề này. –

8

Thread-safety with regular expressions in Java

TÓM TẮT:

Java thường xuyên API biểu đã được thiết kế để cho phép một mẫu biên soạn duy nhất để được chia sẻ trên nhiều hoạt động phù hợp.

Bạn có thể yên tâm gọi Pattern.matcher() trên cùng một khuôn mẫu từ chủ đề khác nhau và an toàn sử dụng quẹt đồng thời. Pattern.matcher() là an toàn để xây dựng các đối sánh mà không cần đồng bộ hóa . Mặc dù phương thức không được đồng bộ hóa, bên trong lớp mẫu , biến số biến động được gọi là biên dịch luôn được đặt sau tạo mẫu và đọc tại số bắt đầu cuộc gọi tới matcher(). Điều này buộc bất kỳ chuỗi nào đề cập đến mẫu để xem chính xác " nội dung của đối tượng đó.

Mặt khác, bạn không nên chia sẻ một đối sánh giữa các chuỗi khác nhau. Hoặc ít nhất, nếu bạn đã từng làm, bạn nên sử dụng đồng bộ hóa rõ ràng.

+2

@akf, BTW, bạn nên lưu ý rằng đó là một trang thảo luận (giống như trang này). Tôi muốn xem xét bất cứ điều gì bạn thấy không có tốt hơn hoặc tồi tệ hơn thông tin mà bạn muốn tìm thấy ở đây (tức là, nó không phải là một từ đúng từ James Gosling). –

2

Xem nhanh mã cho Matcher.java hiển thị một loạt các biến thành viên bao gồm văn bản được khớp, mảng cho nhóm, một vài chỉ mục để duy trì vị trí và một số boolean s cho trạng thái khác. Tất cả điều này trỏ đến trạng thái Matcher có trạng thái không hoạt động tốt nếu được truy cập bởi nhiều Threads. Vì vậy, số JavaDoc:

Trường hợp của lớp này không an toàn để sử dụng bởi nhiều chủ đề đồng thời .

Đây chỉ là vấn đề nếu, như @Bob Cross chỉ ra, bạn không thể sử dụng Matcher riêng biệt Thread s. Nếu bạn cần làm điều này, và bạn nghĩ rằng việc đồng bộ hóa sẽ là một vấn đề đối với mã của bạn, một tùy chọn bạn có là sử dụng một đối tượng lưu trữ ThreadLocal để duy trì một Matcher cho mỗi chuỗi hoạt động.

1

Tóm lại, bạn có thể tái sử dụng (giữ trong các biến tĩnh) Pattern biên soạn (s) và nói với họ để cung cấp cho bạn quẹt mới khi cần thiết để xác nhận những pattens regex chống lại một số chuỗi

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

/** 
* Validation helpers 
*/ 
public final class Validators { 

private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$"; 

private static Pattern email_pattern; 

    static { 
    email_pattern = Pattern.compile(EMAIL_PATTERN); 
    } 

    /** 
    * Check if e-mail is valid 
    */ 
    public static boolean isValidEmail(String email) { 
    Matcher matcher = email_pattern.matcher(email); 
    return matcher.matches(); 
    } 

} 

thấy http://zoomicon.wordpress.com/2012/06/01/validating-e-mails-using-regular-expressions-in-java/ (gần cuối) liên quan đến mẫu RegEx được sử dụng ở trên để xác thực e-mail (trong trường hợp nó không phù hợp với nhu cầu xác thực thư điện tử vì nó được đăng ở đây)

+3

Cảm ơn bạn đã đăng câu trả lời! Vui lòng đảm bảo đọc kỹ [FAQ on Self-Promotion] (http://stackoverflow.com/faq#promotion). Ai đó có thể thấy câu trả lời này và bài đăng trên blog được liên kết và nghĩ rằng bạn đã đăng bài đăng trên blog chỉ để bạn có thể liên kết với nó từ đây. –

+1

Tại sao phải bận tâm với 'static {}'? Bạn có thể inline khởi tạo biến đó và làm cho 'Pattern'' final' là tốt. – TWiStErRob

+1

Tôi thứ hai sự phản đối của TWiStErRob: 'mô hình cuối cùng tĩnh tư nhân emailPattern = Pattern.compile (EMAIL_PATTERN);' là tốt hơn. –

Các vấn đề liên quan