简体   繁体   English

Java:我是否错过了线程问题? (线程内的对象)

[英]Java: Am I Missing the Point of Threads? (Objects within Threads)

I'm trying to learn threads in Java. 我正在尝试学习Java中的线程。 I've followed two different tutorials, but I feel like I'm not really getting the concept. 我遵循了两个不同的教程,但是我觉得我并没有真正理解这个概念。 As I understand it, when you create threads, you use the Thread class, and then embedding your own object within the thread. 据我了解,创建线程时,您将使用Thread类,然后将自己的对象嵌入线程中。 I can do that, but I can't figure out how to access the instance variables within the "embedded" object. 我可以做到,但是我不知道如何访问“嵌入式”对象中的实例变量。

Suppose as a learning exercise, I wanted to create three threads which would go off and do work individually of one another. 假设作为一项学习练习,我想创建三个线程,它们彼此独立工作。 I could define this object to "drive" the threads: 我可以定义该对象来“驱动”线程:

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;
    }
}

Then, in a driver program, I would launch my threads: 然后,在驱动程序中,我将启动线程:

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());
    }
}

Output is: 输出为:

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...

I was surprised when the stooge1.getName() line in main() produced "Thread-0", not "Larry". 当main()中的stooge1.getName()行产生“ Thread-0”而不是“ Larry”时,我感到惊讶。 I was expecting the getName() method I wrote in stoogeObject.java to override and return the instance variable String name in this instance. 我期望在stoogeObject.java中编写的getName()方法将覆盖并返回此实例中的实例变量String name。 Instead, I'm getting the name of the Thread, not the StoogeObject. 相反,我得到的是线程的名称,而不是StoogeObject。

So... The stooge1 thread has a StoogeObject within it, but I don't know how to access its instance variables. 所以... stooge1线程中有一个StoogeObject ,但是我不知道如何访问其实例变量。 More significantly, this example makes me wonder if I'm missing the point of threads. 更重要的是,该示例使我想知道是否缺少线程的要点。 If I want my Larry, Curly, & Moe objects to go off and do productive work AND keep their own instance variables, is using threads the wrong way to go here? 如果我希望我的Larry,Curly和Moe对象停止工作并进行生产工作并保留自己的实例变量,那么使用线程是错误的选择吗? Should I start over, making these objects into processes? 我应该重新开始,将这些对象变成流程吗?

If you want to access the runnable object that you pass to the thread, you need to keep a reference to it. 如果要访问传递给线程的可运行对象,则需要保留对其的引用。

Here is an example: 这是一个例子:

stoogeObject obj = new stoogeObject("Larry", 123);
Thread stooge1 = new Thread(obj);
stooge1.start();
System.out.println(obj.getName());

This will print Larry . 这将打印Larry

Keep in mind that if the name variable from the stoogeObject instance is changed during the thread's runtime, you'll have to wait for that thread to finish (or finish changing the variable) in order to get the correct value. 请记住,如果在线程运行时更改了stoogeObject实例的name变量,则必须等待该线程完成(或完成更改变量)才能获取正确的值。

You can do that by using join() . 您可以使用join()做到这一点。

stoogeObject obj = new stoogeObject("Larry", 123);
Thread stooge1 = new Thread(obj);
stooge1.start();
stooge1.join();
System.out.println(obj.getName());

Here the System.out.println(obj.getName()) statement is executed only after the thread is done. 这里,仅在线程完成之后才执行System.out.println(obj.getName())语句。

I can't figure out how to access the instance variables within the "embedded" object. 我不知道如何访问“嵌入式”对象中的实例变量。

You access them in exactly the same way that you would access the instance variables of any other object. 您以与访问任何其他对象的实例变量完全相同的方式访问它们。

The "embedded" object, FYI, is called the thread's target or the thread's delegate . “嵌入式”对象FYI被称为线程的目标或线程的委托

There is nothing special about the target of a Thread . Thread的目标没有什么特别的。 It's just an object. 这只是一个对象。

I was surprised when the stooge1.getName() line in main() produced "Thread-0", not "Larry". 当main()中的stooge1.getName()行产生“ Thread-0”而不是“ Larry”时,我感到惊讶。 I was expecting ... Instead, I'm getting the name of the Thread, not the StoogeObject. 我期待中...相反,我得到的是线程的名称,而不是StoogeObject。

That's because the Thread object and the StoogeObject are different objects. 这是因为Thread对象和StoogeObject是不同的对象。

this example makes me wonder if I'm missing the point of threads. 这个例子让我想知道我是否缺少线程点。

There are two different ways that threads can be used in a program. 可以在程序中使用线程的两种不同方式。 The first (which is what people think of more often than not) is that threads are how a Java program can make use of more than one CPU if your platform has more than one CPU. 第一个(人们经常想到的是)线程是Java程序如何在平台具有多个CPU的情况下使用多个CPU。 (Virtually all modern servers and workstations have more than one these days, and it's getting to where a lot of cell phones and tablets have more than one as well.) If your platform has, say eight CPUs, then up to eight of your threads may be able to run simultaneously if that many of them are "ready to run." (如今,几乎所有现代服务器和工作站都拥有一个以上的服务器,并且到了很多手机和平板电脑也拥有不止一个的位置。)如果您的平台有八个CPU,那么多达八个线程如果其中许多“准备好运行”,也许可以同时运行。

The second way to use threads in a program is to wait for things. 在程序中使用线程的第二种方法是等待 For example, if your program is a server that has to waits for input from each of N clients, and respond to it; 例如,如果您的程序是一台服务器,必须等待来自N个客户端中的每个客户端的输入,然后对其进行响应; you can structure it as N threads that each just listen to and respond to one client. 您可以将其构造为N个线程,每个线程仅监听和响应一个客户端。 That often makes the code easier to understand. 这通常会使代码更易于理解。 (Just like, it's easier to juggle one ball than it is to juggle N balls). (就像,玩一个球比玩N个球要容易得多)。

is using threads the wrong way to go here? 使用线程是错误的方法吗? Should I start over, making these objects into processes? 我应该重新开始,将这些对象变成流程吗?

Threads can be much more tightly coupled than processes because the threads of a single program all share the same virtual address space (ie, in a Java program, they all share the same heap). 线程可以比进程紧密耦合,因为单个程序的线程都共享相同的虚拟地址空间(即,在Java程序中,它们都共享相同的堆)。 Communication between threads usually is one or two orders of magnitude faster than communication between different processes on the same machine. 线程之间的通信通常比同一计算机上不同进程之间的通信快一两个数量级。

If you need fine-grained communication between them, then they definitely should be threads. 如果您需要它们之间的细粒度通信,那么它们绝对应该是线程。 A good rule of thumb is that, an application should never spawn a new process unless there is a really good reason why it should not be just another thread. 一个好的经验法则是,除非有充分的理由说明应用程序不应该只是另一个线程,否则应用程序永远不要产生新进程。

I was surprised when the stooge1.getName() line in main() produced "Thread-0", not "Larry". 当main()中的stooge1.getName()行产生“ Thread-0”而不是“ Larry”时,我感到惊讶。 I was expecting the getName() method I wrote in stoogeObject.java to override and return the instance variable String name in this instance. 我期望在stoogeObject.java中编写的getName()方法将覆盖并返回此实例中的实例变量String name。 Instead, I'm getting the name of the Thread, not the StoogeObject. 相反,我得到的是线程的名称,而不是StoogeObject。

How is this surprising? 这有多令人惊讶? You never set the thread's name, then you call stooge1.getName() , and stooge1 is the Thread , and you're getting precisely what you asked for: "the name of the Thread". 您从不设置线程的名称,然后调用stooge1.getName() ,而stooge1Thread ,并且您得到的正是您要的内容:“线程的名称”。

The only thing the Thread knows about the Runnable that you pass it is that it has a run() method, it doesn't know or care about any other things you've added to your Runnable implementation. Thread对您传递的Runnable唯一了解的是它具有run()方法,它不知道或不在乎您已添加到Runnable实现中的任何其他内容。

If you want to set the thread's name, either use the Thread constructor that takes a name: 如果要设置线程的名称,请使用带有名称的Thread构造函数:

Thread stooge1 = new Thread(new StoogeObject(...), "Thread's Name");

Or set its name later: 或稍后设置其名称:

stooge1.setName("Thread's Name");

So... The stooge1 thread has a StoogeObject within it, but I don't know how to access its instance variables. 所以... stooge1线程中有一个StoogeObject,但是我不知道如何访问其实例变量。

It's up to you to store and manage your StoogeObject s, and Titus' answer covers this nicely. 存储和管理StoogeObjectStoogeObjectTitus的答案很好地涵盖了这一点。 I just wanted to add a bit on top of that to answer your thread name related question. 我只想在此之上添加一点来回答与线程名称有关的问题。

As a side note: Once you wrap your head around the fundamentals, check out the official high-level concurrency tutorial , particularly the section on "executors". 附带说明:一旦您掌握了基础知识,就可以查看官方的高级并发教程 ,尤其是有关“执行者”的部分。 The Java API provides a few really convenient high-level constructs for concurrency that you might find useful in certain situations. Java API为并发提供了一些非常方便的高级构造,您可能会发现它们在某些情况下很有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM