我试图用Java学习线程。我已经关注了两个不同的教程,但我觉得我并没有真正理解这个概念。据我所知,当你创建线程时,你使用Thread类,然后在线程中嵌入你自己的对象。我可以这样做,但我无法弄清楚如何访问" embedded"中的实例变量。对象
假设作为一个学习练习,我想创建三个线程,这些线程将会相互独立地工作。我可以将此对象定义为" drive"线程:
public class StoogeObject implements Runnable {
String name;
int data;
public StoogeObject(String name, int data){
this.name=name;
this.data=data;
}
@Override
public void run() {
System.out.println("Thread "+this.name+" has this data: "+this.data);
// Do useful work here
System.out.println("Thread "+this.name+" is exiting...");
}
public String getName(){
return this.name;
}
}
然后,在驱动程序中,我将启动我的线程:
public class driver {
public static void main(String[] args){
Thread stooge1 = new Thread(new StoogeObject("Larry", 123));
Thread stooge2 = new Thread(new StoogeObject("Curly", 456));
Thread stooge3 = new Thread(new StoogeObject("Moe", 789));
stooge1.start();
stooge2.start();
stooge3.start();
if(stooge1.isAlive())
System.out.println("From main(): "+stooge1.getName());
}
}
输出是:
From main(): Thread-0
Thread Larry has this data: 123
Thread Curly has this data: 456
Thread Moe has this data: 789
Thread Larry is exiting...
Thread Curly is exiting...
Thread Moe is exiting...
当main()中的stooge1.getName()行生成" Thread-0"而不是" Larry"时,我感到很惊讶。我期待我在stoogeObject.java中编写的getName()方法覆盖并返回此实例中的实例变量String name。相反,我获得了Thread的名称,而不是StoogeObject。
所以... stooge1
帖子中有StoogeObject
,但我不知道如何访问其实例变量。更重要的是,这个例子让我想知道我是否错过了线程点。如果我想要我的拉里,卷曲和& Moe对象去做有成效的工作并保留自己的实例变量,是用错误的方式去线程吗?我应该重新开始,将这些对象变成进程吗?
答案 0 :(得分:2)
如果要访问传递给线程的runnable对象,则需要保留对它的引用。
以下是一个例子:
stoogeObject obj = new stoogeObject("Larry", 123);
Thread stooge1 = new Thread(obj);
stooge1.start();
System.out.println(obj.getName());
这将打印Larry
。
请记住,如果在线程的运行时期间更改name
实例中的stoogeObject
变量,则必须等待该线程完成(或完成)更改变量)以获得正确的值。
您可以使用join()
。
stoogeObject obj = new stoogeObject("Larry", 123);
Thread stooge1 = new Thread(obj);
stooge1.start();
stooge1.join();
System.out.println(obj.getName());
此处System.out.println(obj.getName())
语句仅在线程完成后执行。
答案 1 :(得分:2)
我无法弄清楚如何访问" embedded"中的实例变量。对象
您访问它们的方式与访问任何其他对象的实例变量的方式完全相同。
"嵌入式"对象,仅供参考,被称为线程的目标或线程的委托。
Thread
的目标没有什么特别之处。它只是一个对象。
当main()中的stooge1.getName()行生成" Thread-0"而不是" Larry"时,我感到很惊讶。我在期待......相反,我得到了Thread的名字,而不是StoogeObject。
那是因为Thread
对象和StoogeObject
是不同的对象。
这个例子让我想知道我是否错过了线程点。
线程可以在程序中使用两种不同的方式。第一个(这是人们经常想到的)是线程是Java程序如果你的平台有多个CPU,如何使用多个CPU。 (现在几乎所有的现代服务器和工作站都有不止一个,而且很多手机和平板电脑都有不止一个。)如果您的平台有八个CPU,那么最多如果其中许多线程已经准备就绪,那么你的八个线程可以同时运行。"
在程序中使用线程的第二种方法是等待。例如,如果您的程序是必须等待来自N个客户端的每个客户端的输入并响应它的服务器;你可以把它构造成N个线程,每个线程只听一个客户端并响应。这通常使代码更容易理解。 (就像,玩弄一个球比玩弄N球更容易)。
使用错误的方式去这里吗?我应该重新开始,将这些对象变成进程吗?
线程可以比进程紧密耦合,因为单个程序的线程都共享相同的虚拟地址空间(即,在Java程序中,它们都共享相同的堆)。线程之间的通信通常比同一台机器上不同进程之间的通信快一到两个数量级。
如果你需要细粒度的沟通,那么他们肯定应该是线程。一个好的经验法则是,应用程序永远不应该生成一个新进程,除非有一个非常好的理由说明为什么它不应该只是另一个线程。
答案 2 :(得分:1)
当main()中的stooge1.getName()行生成“Thread-0”而非“Larry”时,我感到很惊讶。我期待我在stoogeObject.java中编写的getName()方法覆盖并返回此实例中的实例变量String name。相反,我得到了Thread的名称,而不是StoogeObject。
这有多令人惊讶?你永远不会设置主题的名字,然后你打电话给stooge1.getName()
,而stooge1
就是Thread
,你得到的正是你所要求的:“主题的名字”。< / p>
Thread
唯一知道你传递给它的Runnable
就是它有一个run()
方法,它不知道或不关心你做过的任何其他事情已添加到您的Runnable
实施中。
如果要设置线程的名称,请使用带有名称的Thread
构造函数:
Thread stooge1 = new Thread(new StoogeObject(...), "Thread's Name");
或稍后设置其名称:
stooge1.setName("Thread's Name");
所以... stooge1线程中有一个StoogeObject,但我不知道如何访问它的实例变量。
由您来存储和管理StoogeObject
,Titus' answer很好地涵盖了这一点。我只是想补充一点来回答你的线程名称相关的问题。
作为旁注:一旦你绕过基本面,请查看官方high-level concurrency tutorial,特别是关于“执行者”的部分。 Java API提供了一些非常方便的并发高级构造,您可能会发现它们在某些情况下很有用。