Bất cứ ai có thể đề nghị với tôi làm thế nào tôi có thể truyền một tham số cho một chủ đề?
Ngoài ra, làm thế nào nó hoạt động cho các lớp ẩn danh?
Consumer<T>
.
Bất cứ ai có thể đề nghị với tôi làm thế nào tôi có thể truyền một tham số cho một chủ đề?
Ngoài ra, làm thế nào nó hoạt động cho các lớp ẩn danh?
Consumer<T>
.
Câu trả lời:
Bạn cần truyền tham số trong hàm tạo cho đối tượng Runnable:
public class MyRunnable implements Runnable {
public MyRunnable(Object parameter) {
// store parameter for later user
}
public void run() {
}
}
và gọi nó như vậy:
Runnable r = new MyRunnable(param_value);
new Thread(r).start();
r
sẽ có cùng một đối số, vì vậy nếu chúng ta muốn chuyển các đối số khác nhau cho nhiều Chủ đề đang chạy, MyThread
chúng ta cần tạo một phiên bản mới MyThread
bằng cách sử dụng đối số mong muốn cho mỗi Chủ đề. Nói cách khác, để có được một luồng và chạy, chúng ta cần tạo hai đối tượng: Thread và MyThread. Đây có được coi là xấu, hiệu suất khôn ngoan?
Để trả lời các chỉnh sửa câu hỏi ở đây là cách nó hoạt động cho các lớp Ẩn danh
final X parameter = ...; // the final is important
Thread t = new Thread(new Runnable() {
p = parameter;
public void run() {
...
};
t.start();
Bạn có một lớp mở rộng Thread (hoặc thực hiện Runnable) và hàm tạo với các tham số bạn muốn truyền. Sau đó, khi bạn tạo chủ đề mới, bạn phải truyền vào các đối số và sau đó bắt đầu chủ đề, đại loại như thế này:
Thread t = new MyThread(args...);
t.start();
Runnable là một giải pháp tốt hơn nhiều so với Thread BTW. Vì vậy, tôi thích:
public class MyRunnable implements Runnable {
private X parameter;
public MyRunnable(X parameter) {
this.parameter = parameter;
}
public void run() {
}
}
Thread t = new Thread(new MyRunnable(parameter));
t.start();
Câu trả lời này về cơ bản giống như câu hỏi tương tự này: Cách truyền tham số cho đối tượng Thread
parameter
trực tiếp từ run()
phương thức mà không sử dụng một trường nào p
cả. Nó dường như làm việc. Có một số điều đa luồng tinh tế mà tôi đang thiếu bằng cách không sao chép parameter
vào p
trước?
)
ví dụ đầu tiên
final X parameter
trước new Runnable()
, sau đó tôi có thể truy cập parameter
vào bên trong run()
. Tôi không cần phải làm thêm p = parameter
.
final
không còn quan trọng nữa; đủ để biến cuối cùng có hiệu quả (mặc dù nó không có hại gì)
thông qua hàm tạo của lớp Runnable hoặc Thread
class MyThread extends Thread {
private String to;
public MyThread(String to) {
this.to = to;
}
@Override
public void run() {
System.out.println("hello " + to);
}
}
public static void main(String[] args) {
new MyThread("world!").start();
}
@Override
cho?
@Override
nói rõ rằng nó đang ghi đè phương thức trừu tượng trong lớp Thread.
Câu trả lời này đến rất muộn, nhưng có lẽ ai đó sẽ thấy nó hữu ích. Đó là về cách truyền (các) tham số cho một Runnable
mà thậm chí không khai báo lớp có tên (tiện dụng cho inliners):
String someValue = "Just a demo, really...";
new Thread(new Runnable() {
private String myParam;
public Runnable init(String myParam) {
this.myParam = myParam;
return this;
}
@Override
public void run() {
System.out.println("This is called from another thread.");
System.out.println(this.myParam);
}
}.init(someValue)).start();
Tất nhiên bạn có thể hoãn thực hiện start
đến một số thời điểm thuận tiện hoặc thích hợp hơn. Và tùy thuộc vào bạn, đâu sẽ là chữ ký của init
phương thức (vì vậy nó có thể mất nhiều hơn và / hoặc các đối số khác nhau) và tất nhiên ngay cả tên của nó, nhưng về cơ bản, bạn có một ý tưởng.
Trong thực tế, cũng có một cách khác để truyền tham số cho một lớp ẩn danh, với việc sử dụng các khối khởi tạo. Xem xét điều này:
String someValue = "Another demo, no serious thing...";
int anotherValue = 42;
new Thread(new Runnable() {
private String myParam;
private int myOtherParam;
{
this.myParam = someValue;
this.myOtherParam = anotherValue;
}
@Override
public void run() {
System.out.println("This comes from another thread.");
System.out.println(this.myParam + ", " + this.myOtherParam);
}
}).start();
Vì vậy, tất cả xảy ra bên trong khối khởi tạo.
this.myParam
sau đó có thực sự cần thiết? Bạn không thể bỏ các biến riêng tư và tham khảo biến từ phạm vi bên ngoài? Tôi hiểu (tất nhiên) rằng điều này có một số hàm ý, chẳng hạn như biến được mở để thay đổi sau khi bắt đầu chuỗi.
Khi bạn tạo một chủ đề, bạn cần một thể hiện của Runnable
. Cách dễ nhất để truyền tham số sẽ là truyền tham số đó dưới dạng đối số cho hàm tạo:
public class MyRunnable implements Runnable {
private volatile String myParam;
public MyRunnable(String myParam){
this.myParam = myParam;
...
}
public void run(){
// do something with myParam here
...
}
}
MyRunnable myRunnable = new myRunnable("Hello World");
new Thread(myRunnable).start();
Nếu sau đó bạn muốn thay đổi tham số trong khi luồng đang chạy, bạn có thể chỉ cần thêm một phương thức setter vào lớp có thể chạy của bạn:
public void setMyParam(String value){
this.myParam = value;
}
Khi bạn có thứ này, bạn có thể thay đổi giá trị của tham số bằng cách gọi như thế này:
myRunnable.setMyParam("Goodbye World");
Tất nhiên, nếu bạn muốn kích hoạt một hành động khi thay đổi tham số, bạn sẽ phải sử dụng các khóa, điều này làm cho mọi thứ phức tạp hơn đáng kể.
Để tạo một chủ đề, bạn thường tạo triển khai Runnable của riêng bạn. Truyền tham số cho luồng trong hàm tạo của lớp này.
class MyThread implements Runnable{
private int a;
private String b;
private double c;
public MyThread(int a, String b, double c){
this.a = a;
this.b = b;
this.c = c;
}
public void run(){
doSomething(a, b, c);
}
}
Bạn có thể mở rộng hoặc cung cấp các tham số theo ý muốn. Có những ví dụ đơn giản trong các tài liệu . Tôi sẽ chuyển chúng ở đây:Thread
class
Runnable
class
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeThread p = new PrimeThread(143);
p.start();
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
Viết một lớp thực hiện Runnable và chuyển bất cứ thứ gì bạn cần vào một hàm tạo được xác định phù hợp hoặc viết một lớp mở rộng Thread bằng một hàm tạo được xác định phù hợp gọi super () với các tham số thích hợp.
Kể từ Java 8, bạn có thể sử dụng lambda để nắm bắt các tham số cuối cùng có hiệu quả . Ví dụ:
final String param1 = "First param";
final int param2 = 2;
new Thread(() -> {
// Do whatever you want here: param1 and param2 are in-scope!
System.out.println(param1);
System.out.println(param2);
}).start();
Trong Java 8, bạn có thể sử dụng các lambda
biểu thức với API đồng thời & ExecutorService
dưới dạng thay thế cấp cao hơn để làm việc trực tiếp với các luồng:
newCachedThreadPool()
Tạo một nhóm luồng tạo ra các luồng mới khi cần, nhưng sẽ sử dụng lại các luồng được xây dựng trước đó khi chúng có sẵn. Các nhóm này thường sẽ cải thiện hiệu suất của các chương trình thực thi nhiều tác vụ không đồng bộ trong thời gian ngắn.
private static final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(() -> {
myFunction(myParam1, myParam2);
});
Xem thêm executors
javadocs .
Tôi biết rằng tôi trễ vài năm, nhưng tôi đã gặp phải vấn đề này và đã thực hiện một cách tiếp cận không chính thống. Tôi muốn làm điều đó mà không cần tạo một lớp mới, vì vậy đây là những gì tôi nghĩ ra:
int x = 0;
new Thread((new Runnable() {
int x;
public void run() {
// stuff with x and whatever else you want
}
public Runnable pass(int x) {
this.x = x;
return this;
}
}).pass(x)).start();
Tham số truyền qua các phương thức start () và run ():
// Tester
public static void main(String... args) throws Exception {
ThreadType2 t = new ThreadType2(new RunnableType2(){
public void run(Object object) {
System.out.println("Parameter="+object);
}});
t.start("the parameter");
}
// New class 1 of 2
public class ThreadType2 {
final private Thread thread;
private Object objectIn = null;
ThreadType2(final RunnableType2 runnableType2) {
thread = new Thread(new Runnable() {
public void run() {
runnableType2.run(objectIn);
}});
}
public void start(final Object object) {
this.objectIn = object;
thread.start();
}
// If you want to do things like setDaemon(true);
public Thread getThread() {
return thread;
}
}
// New class 2 of 2
public interface RunnableType2 {
public void run(Object object);
}
Bạn có thể lấy được một lớp từ Runnable và trong quá trình xây dựng (giả sử) truyền tham số vào.
Sau đó khởi chạy nó bằng Thread.start (Runnable r);
Nếu bạn có nghĩa là trong khi luồng đang chạy, thì chỉ cần giữ một tham chiếu đến đối tượng dẫn xuất của bạn trong luồng gọi và gọi các phương thức setter thích hợp (đồng bộ hóa khi thích hợp)
Không, bạn không thể truyền tham số cho run()
phương thức. Chữ ký cho bạn biết rằng (nó không có tham số). Có lẽ cách dễ nhất để làm điều này là sử dụng một đối tượng được xây dựng có mục đích lấy tham số trong hàm tạo và lưu trữ nó trong một biến cuối cùng:
public class WorkingTask implements Runnable
{
private final Object toWorkWith;
public WorkingTask(Object workOnMe)
{
toWorkWith = workOnMe;
}
public void run()
{
//do work
}
}
//...
Thread t = new Thread(new WorkingTask(theData));
t.start();
Khi bạn làm điều đó - bạn phải cẩn thận về tính toàn vẹn dữ liệu của đối tượng bạn chuyển vào 'WorkTask'. Bây giờ dữ liệu sẽ tồn tại trong hai luồng khác nhau, do đó bạn phải chắc chắn rằng đó là Thread Safe.
Một lựa chọn nữa; Cách tiếp cận này cho phép bạn sử dụng mục Runnable như một lệnh gọi hàm không đồng bộ. Nếu nhiệm vụ của bạn không cần trả về kết quả, ví dụ: nó chỉ thực hiện một số hành động bạn không cần lo lắng về cách bạn trả lại "kết quả".
Mẫu này cho phép bạn sử dụng lại một mục, trong đó bạn cần một số loại trạng thái nội bộ. Khi không truyền (các) tham số trong chăm sóc hàm tạo là cần thiết để làm trung gian truy cập chương trình vào tham số. Bạn có thể cần kiểm tra thêm nếu trường hợp sử dụng của bạn liên quan đến những người gọi khác nhau, v.v.
public class MyRunnable implements Runnable
{
private final Boolean PARAMETER_LOCK = false;
private X parameter;
public MyRunnable(X parameter) {
this.parameter = parameter;
}
public void setParameter( final X newParameter ){
boolean done = false;
synchronize( PARAMETER_LOCK )
{
if( null == parameter )
{
parameter = newParameter;
done = true;
}
}
if( ! done )
{
throw new RuntimeException("MyRunnable - Parameter not cleared." );
}
}
public void clearParameter(){
synchronize( PARAMETER_LOCK )
{
parameter = null;
}
}
public void run() {
X localParameter;
synchronize( PARAMETER_LOCK )
{
localParameter = parameter;
}
if( null != localParameter )
{
clearParameter(); //-- could clear now, or later, or not at all ...
doSomeStuff( localParameter );
}
}
}
Chủ đề t = new Chủ đề (mới MyRunnable (tham số)); t.start ();
Nếu bạn cần kết quả xử lý, bạn cũng sẽ cần phối hợp hoàn thành MyRunnable khi tác vụ phụ kết thúc. Bạn có thể chuyển cuộc gọi lại hoặc chỉ chờ trong Chủ đề 't', v.v.
Đối với mục đích gọi lại, tôi thường triển khai chung chung Runnable
với (các) tham số đầu vào:
public interface Runnable<TResult> {
void run(TResult result);
}
Cách sử dụng rất đơn giản:
myManager.doCallbackOperation(new Runnable<MyResult>() {
@Override
public void run(MyResult result) {
// do something with the result
}
});
Trong quản lý:
public void doCallbackOperation(Runnable<MyResult> runnable) {
new AsyncTask<Void, Void, MyResult>() {
@Override
protected MyResult doInBackground(Void... params) {
// do background operation
return new MyResult(); // return resulting object
}
@Override
protected void onPostExecute(MyResult result) {
// execute runnable passing the result when operation has finished
runnable.run(result);
}
}.execute();
}
Tạo một biến cục bộ trong lớp của bạn đó extends Thread
hoặc implements Runnable
.
public class Extractor extends Thread {
public String webpage = "";
public Extractor(String w){
webpage = w;
}
public void setWebpage(String l){
webpage = l;
}
@Override
public void run() {// l is link
System.out.println(webpage);
}
public String toString(){
return "Page: "+webpage;
}}
Bằng cách này, bạn có thể vượt qua một biến khi bạn chạy nó.
Extractor e = new Extractor("www.google.com");
e.start();
Đầu ra:
"www.google.com"