繁体   English   中英

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

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

我正在尝试学习Java中的线程。 我遵循了两个不同的教程,但是我觉得我并没有真正理解这个概念。 据我了解,创建线程时,您将使用Thread类,然后将自己的对象嵌入线程中。 我可以做到,但是我不知道如何访问“嵌入式”对象中的实例变量。

假设作为一项学习练习,我想创建三个线程,它们彼此独立工作。 我可以定义该对象来“驱动”线程:

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。 相反,我得到的是线程的名称,而不是StoogeObject。

所以... stooge1线程中有一个StoogeObject ,但是我不知道如何访问其实例变量。 更重要的是,该示例使我想知道是否缺少线程的要点。 如果我希望我的Larry,Curly和Moe对象停止工作并进行生产工作并保留自己的实例变量,那么使用线程是错误的选择吗? 我应该重新开始,将这些对象变成流程吗?

如果要访问传递给线程的可运行对象,则需要保留对其的引用。

这是一个例子:

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

这将打印Larry

请记住,如果在线程运行时更改了stoogeObject实例的name变量,则必须等待该线程完成(或完成更改变量)才能获取正确的值。

您可以使用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())语句。

我不知道如何访问“嵌入式”对象中的实例变量。

您以与访问任何其他对象的实例变量完全相同的方式访问它们。

“嵌入式”对象FYI被称为线程的目标或线程的委托

Thread的目标没有什么特别的。 这只是一个对象。

当main()中的stooge1.getName()行产生“ Thread-0”而不是“ Larry”时,我感到惊讶。 我期待中...相反,我得到的是线程的名称,而不是StoogeObject。

这是因为Thread对象和StoogeObject是不同的对象。

这个例子让我想知道我是否缺少线程点。

可以在程序中使用线程的两种不同方式。 第一个(人们经常想到的是)线程是Java程序如何在平台具有多个CPU的情况下使用多个CPU。 (如今,几乎所有现代服务器和工作站都拥有一个以上的服务器,并且到了很多手机和平板电脑也拥有不止一个的位置。)如果您的平台有八个CPU,那么多达八个线程如果其中许多“准备好运行”,也许可以同时运行。

在程序中使用线程的第二种方法是等待 例如,如果您的程序是一台服务器,必须等待来自N个客户端中的每个客户端的输入,然后对其进行响应; 您可以将其构造为N个线程,每个线程仅监听和响应一个客户端。 这通常会使代码更易于理解。 (就像,玩一个球比玩N个球要容易得多)。

使用线程是错误的方法吗? 我应该重新开始,将这些对象变成流程吗?

线程可以比进程紧密耦合,因为单个程序的线程都共享相同的虚拟地址空间(即,在Java程序中,它们都共享相同的堆)。 线程之间的通信通常比同一计算机上不同进程之间的通信快一两个数量级。

如果您需要它们之间的细粒度通信,那么它们绝对应该是线程。 一个好的经验法则是,除非有充分的理由说明应用程序不应该只是另一个线程,否则应用程序永远不要产生新进程。

当main()中的stooge1.getName()行产生“ Thread-0”而不是“ Larry”时,我感到惊讶。 我期望在stoogeObject.java中编写的getName()方法将覆盖并返回此实例中的实例变量String name。 相反,我得到的是线程的名称,而不是StoogeObject。

这有多令人惊讶? 您从不设置线程的名称,然后调用stooge1.getName() ,而stooge1Thread ,并且您得到的正是您要的内容:“线程的名称”。

Thread对您传递的Runnable唯一了解的是它具有run()方法,它不知道或不在乎您已添加到Runnable实现中的任何其他内容。

如果要设置线程的名称,请使用带有名称的Thread构造函数:

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

或稍后设置其名称:

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

所以... stooge1线程中有一个StoogeObject,但是我不知道如何访问其实例变量。

存储和管理StoogeObjectStoogeObjectTitus的答案很好地涵盖了这一点。 我只想在此之上添加一点来回答与线程名称有关的问题。

附带说明:一旦您掌握了基础知识,就可以查看官方的高级并发教程 ,尤其是有关“执行者”的部分。 Java API为并发提供了一些非常方便的高级构造,您可能会发现它们在某些情况下很有用。

暂无
暂无

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

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