Herkes bana nasıl bir iş parçacığına bir parametre geçirebilir miyim önerebilir?
Ayrıca, anonim sınıflar için nasıl çalışır?
Consumer<T>
.
Herkes bana nasıl bir iş parçacığına bir parametre geçirebilir miyim önerebilir?
Ayrıca, anonim sınıflar için nasıl çalışır?
Consumer<T>
.
Yanıtlar:
Yapıcıdaki parametreyi Runnable nesnesine geçirmeniz gerekir:
public class MyRunnable implements Runnable {
public MyRunnable(Object parameter) {
// store parameter for later user
}
public void run() {
}
}
ve bu şekilde çağırın:
Runnable r = new MyRunnable(param_value);
new Thread(r).start();
r
aynı argümana sahip olacağı anlamına gelir , bu nedenle birden fazla Konuya farklı argümanlar iletmek istiyorsak, her Konu için istenen argümanı kullanarak MyThread
yeni bir MyThread
örnek oluşturmamız gerekir . Başka bir deyişle, bir iş parçacığını çalıştırmak ve çalıştırmak için iki nesne oluşturmamız gerekir: Thread ve MyThread. Bu kötü, performans açısından mı değerlendiriliyor?
Soru düzenlemelerine yanıt olarak, Anonim sınıflar için nasıl çalıştığı
final X parameter = ...; // the final is important
Thread t = new Thread(new Runnable() {
p = parameter;
public void run() {
...
};
t.start();
İş parçacığını genişleten (veya Runnable uygulayan) bir sınıfınız ve geçmek istediğiniz parametreleri içeren bir kurucunuz var. Sonra, yeni bir iş parçacığı oluşturduğunuzda, bağımsız değişkenleri iletmek ve sonra iş parçacığı, böyle bir şey başlatmak gerekir:
Thread t = new MyThread(args...);
t.start();
Runnable, Thread BTW'den çok daha iyi bir çözümdür. Bu yüzden tercih ederim:
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();
Bu yanıt temel olarak şu benzer soru ile aynıdır: Parametreler bir Thread nesnesine nasıl aktarılır
parameter
doğrudan run()
yöntemden erişiyorum p
. İşe yarıyor gibi görünüyor. Ben kopyalayarak vermeyerek Eksik bazı ince çoklu şey var mı parameter
hiç p
önceden?
)
İlk örnekte bir eksik olduğunu düşünüyorum
final X parameter
önce new Runnable()
çizgi, o zaman ben erişebilir parameter
içeride run()
. Ekstra yapmam gerekmiyordu p = parameter
.
final
artık o kadar önemli değil; değişken olması durumunda, yeterli etkin bir nihai (hiçbir zarar having o does rağmen)
Runnable veya Thread sınıfının kurucusu aracılığıyla
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
?
@Override
Açık bir şekilde, Thread sınıfındaki soyut yöntemi geçersiz kıldığını açıkça belirtir.
Bu cevap çok geç geliyor, ama belki birisi faydalı bulacaktır. Bu, Runnable
adlandırılmış sınıfı bile bildirmeden bir parametreye / parametrelere nasıl aktarılacağıyla ilgilidir (satır içi için kullanışlı):
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();
Tabii ki uygulanmasını start
daha uygun veya uygun bir an için erteleyebilirsiniz . Ve init
yöntemin imzası ne olacaktır (bu yüzden daha fazla ve / veya farklı argümanlar alabilir) ve elbette onun adı bile, ama temelde bir fikir elde edersiniz.
Aslında, başlangıç parametrelerini kullanarak bir parametreyi anonim bir sınıfa geçirmenin başka bir yolu da vardır. Bunu düşün:
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();
Böylece her şey başlatıcı bloğunun içinde olur.
this.myParam
zaman gerçekten gerekli mi? Özel değişkenleri bırakıp dış kapsamdaki değişkene atıfta bulunamaz mısınız? (Tabii ki) iş parçacığını başlattıktan sonra değişken değişime açık olması gibi bazı sonuçları olduğunu anlıyorum.
Bir iş parçacığı oluşturduğunuzda, bir örneğine ihtiyacınız vardır Runnable
. Bir parametreyi iletmenin en kolay yolu, parametreyi yapıcıya bir argüman olarak iletmektir:
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();
Daha sonra iş parçacığı çalışırken parametreyi değiştirmek isterseniz, runnable sınıfınıza bir ayarlayıcı yöntemi ekleyebilirsiniz:
public void setMyParam(String value){
this.myParam = value;
}
Bunu yaptıktan sonra, şu şekilde çağırarak parametrenin değerini değiştirebilirsiniz:
myRunnable.setMyParam("Goodbye World");
Tabii ki, parametre değiştirildiğinde bir eylemi tetiklemek istiyorsanız, kilitleri kullanmanız gerekir, bu da işleri daha karmaşık hale getirir.
Bir iş parçacığı oluşturmak için normalde kendi Runnable uygulamasını oluşturursunuz. Parametreleri bu sınıfın yapıcısındaki iş parçacığına iletin.
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);
}
}
Ya uzatabilirsiniz veya ve istediğiniz kadar parametreleri sunar. Dokümanlarda basit örnekler var . Onları buraya taşıyacağım: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();
Runnable'ı uygulayan bir sınıf yazın ve ihtiyacınız olan her şeyi uygun şekilde tanımlanmış bir kurucuya iletin ya da Thread'ı uygun parametrelerle super () çağıran uygun tanımlı bir kurucu ile genişleten bir sınıf yazın.
Java 8'den itibaren, etkili olan son parametreleri yakalamak için bir lambda kullanabilirsiniz . Örneğin:
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();
Java 8'de kullanabileceğiniz lambda
ile ifadeleri eşzamanlılık API & ExecutorService
doğrudan parçacığı ile çalışmak için daha yüksek düzeyde yerine:
newCachedThreadPool()
Gerektiğinde yeni iş parçacıkları oluşturan, ancak önceden oluşturulmuş iş parçacıklarını kullanılabilir olduğunda yeniden kullanacak bir iş parçacığı havuzu oluşturur. Bu havuzlar genellikle kısa ömürlü birçok zaman uyumsuz görevi yürüten programların performansını artıracaktır.
private static final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(() -> {
myFunction(myParam1, myParam2);
});
Birkaç yıl geç kaldığımı biliyorum, ama bu konuyla karşılaştım ve alışılmadık bir yaklaşım izledim. Ben yeni bir sınıf yapmadan yapmak istedim, bu yüzden ben geldi budur:
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();
Start () ve run () yöntemlerinden geçen parametre:
// 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);
}
Runnable'dan bir sınıf türetebilirsiniz ve inşaat sırasında (diyelim) parametreyi iletin.
Sonra Thread.start (Runnable r) kullanarak başlatın;
Eğer demek istediğin iken çalışan iş parçacığı, o zaman sadece çağıran iş parçacığı içinde türetilmiş bir nesneye bir başvuru tutun ve uygun ayarlayıcı yöntemleri çağırmak (senkronize uygun olduğunda)
Hayır, parametreye run()
yönteme geçemezsiniz . İmza size bunu söyler (parametresi yoktur). Muhtemelen bunu yapmanın en kolay yolu, yapıcıda bir parametre alan ve bir son değişkente saklayan amaca yönelik bir nesne kullanmak olacaktır:
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();
Bunu yaptıktan sonra - 'WorkingTask'a ilettiğiniz nesnenin veri bütünlüğüne dikkat etmelisiniz. Veriler artık iki farklı iş parçacığında mevcut olacaktır, bu nedenle iş parçacığının Güvenli olduğundan emin olmanız gerekir.
Başka bir seçenek; bu yaklaşım Runnable öğesini eşzamansız işlev çağrısı gibi kullanmanızı sağlar. Görevinizin bir sonuç döndürmesi gerekmiyorsa, örneğin sadece bir "sonucu" nasıl geri verdiğiniz konusunda endişelenmenize gerek olmayan bazı eylemleri gerçekleştirir.
Bu desen, bir tür dahili duruma ihtiyaç duyduğunuz bir öğeyi yeniden kullanmanızı sağlar. Kurucuda parametre (ler) geçirilmediğinde programların parametrelere erişimine aracılık etmek için bakım gerekir. Kullanım durumunuz farklı arayanlar vb. İçeriyorsa daha fazla kontrole ihtiyacınız olabilir.
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 );
}
}
}
Konu t = yeni Konu (yeni MyRunnable (parametre)); t.start ();
İşlemenin bir sonucuna ihtiyacınız varsa, alt görev tamamlandığında MyRunnable'ın tamamlanmasını da koordine etmeniz gerekir. Bir aramayı geri verebilir veya sadece 't', vb.
Geri arama amaçları için genellikle kendi genel kodumu Runnable
girdi parametreleri ile uygularım :
public interface Runnable<TResult> {
void run(TResult result);
}
Kullanımı basit:
myManager.doCallbackOperation(new Runnable<MyResult>() {
@Override
public void run(MyResult result) {
// do something with the result
}
});
Yöneticide:
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();
}
Sınıfınızda yerel bir değişken oluşturun extends Thread
veya 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;
}}
Bu şekilde, bir değişkeni çalıştırdığınızda iletebilirsiniz.
Extractor e = new Extractor("www.google.com");
e.start();
Çıktı:
"www.google.com"