您的问题表明您可能不完全理解“线程”的含义。
当我们学习编程时,他们告诉我们计算机程序是一系列指令,他们告诉我们计算机执行这些指令,从一些良好的开始定义的入口点(例如,main() 例程)。
好的,但是当我们谈论多线程程序时,仅仅说“计算机”执行我们的代码是不够的。现在我们说 threads 执行我们的代码。每个线程对它在程序中的位置都有自己的想法,如果两个或多个线程碰巧同时在同一个函数中执行,那么每个线程都有自己的函数参数和局部变量的私有副本。
所以,你问:
Java 程序是否默认只创建 1 个线程?
Java 程序总是从一个执行你的代码的线程开始,通常还有几个其他线程执行 JVM 代码。您通常不需要了解 JVM 线程。执行您的代码的一个线程在您的main() 例程的开头开始其工作。
程序员通常将初始线程称为“主线程”。可能他们这样称呼它是因为它调用main(),但要小心!该名称可能会产生误导:JVM 不会将“主线程”与多线程 Java 程序中的任何其他线程区别对待。
如果我们创建一个多线程程序,多个线程何时访问Java对象的相同代码?
线程只做你的程序告诉他们做的事情。如果您为两个不同的线程编写代码来调用同一个函数,那么它们就是这样做的。但是,让我们把这个问题分解一下......
...首先,我们如何创建一个多线程程序?
当您的代码告诉程序变为多线程时,程序变为多线程。在一个简单的例子中,它看起来像这样:
class MyRunnable implements Runnable {
public void run() {
DoSomeUsefulThing();
DoSomeOtherThing();
}
}
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
...
当您程序中的某个其他线程调用t.start() 时,Java 会创建一个新线程。 (注意!Thread 实例 t 不是线程。它只是一个句柄,您的程序可以使用它来启动线程并查询其线程的状态并控制它。)
当新线程开始执行程序指令时,它将通过调用r.run()开始。如您所见,r.run() 的主体将导致新线程到DoSomeUsefulThing(),然后在r.run() 返回之前DoSomeOtherThing()。
当r.run() 返回时,线程结束(又名“终止”,又名“死亡”)。
所以,
多个线程何时访问 Java 对象的相同代码?
当您的代码让他们这样做时。让我们在上面的示例中添加一行:
...
Thread t = new Thread(r);
t.start();
DoSomeUsefulThing();
...
请注意,主线程在启动新线程后没有停止。它继续执行t.start() 调用之后的任何内容。在这种情况下,它接下来要做的就是调用DoSomeUsefulThing()。但这与程序告诉新线程要做的事情一样!如果 DoSomeUsefulThing() 需要很长时间才能完成,那么两个线程将同时执行此操作...因为这是程序告诉它们执行的操作。
请展示一个关注线程安全的示例程序
我刚刚做了。
想想DoSomeUsefulThing() 可能在做什么。如果它在做一些有用的事情,那么它几乎肯定是在对某处的某些数据 做一些事情。但是,我没有告诉它对什么数据进行操作,所以很有可能,两个线程同时对相同的数据做某事。
这很有可能不会很好。
解决此问题的一种方法是告诉函数要处理哪些数据。
class MyDataClass { ... }
Class MyRunnable implements Runnable {
private MyDataClass data;
public MyRunnable(MyDataClass data) {
this.data = data;
}
public void run() {
DoSomeUsefulThingWITH(data);
DoSomeOtherThingWITH(data);
}
}
MyDataClass dat_a = new MyDataClass(...);
MyDataClass dat_b = new MyDataClass(...);
MyRunnable r = new MyRunnable(dat_a);
Thread t = new Thread(r);
t.start();
DoSomeUsefulThingWITH(dat_b);
那里!现在这两个线程在做同样的事情,但是他们对不同的数据做这件事。
但是如果您希望它们对相同的数据进行操作怎么办?
这是一个不同问题的主题。谷歌“互斥”开始。