线程会共享进程范围内的资源,例如内存句柄和文件句柄,但每个线程都有各自的程序计数器、栈及局部变量等。线程还提供了一种直观的分解模式来充分利用多处理器系统中的硬件并行性,而在同一个程序中的多个线程还可以被同时调度到多个CPU上运行。线程也被称为轻量级进程。在大多数现代操作系统中,都是以线程为基本的调度单位,而不是进程。同一个进程中的所有线程都将共享进程的内存地址空间,因此这些线程都能访问相同的成员变量并在同一个堆上分配对象。
成员变量:
package deep;
public class MemberVariableThread implements Runnable {
private int i;// 成员变量被初始化为0
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + i++);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (50 == i) {
break;
}
}
}
}
package deep;
public class Test {
public static void main(String[] args) {
MemberVariableThread memberVariableThread = new MemberVariableThread();
Thread thread1 = new Thread(memberVariableThread);
Thread thread2 = new Thread(memberVariableThread);
thread1.start();
thread2.start();
}
}
运行结果:
Thread-0:0
Thread-1:0
Thread-0:1
Thread-1:2
Thread-0:3
Thread-1:4
Thread-0:5
Thread-1:5
Thread-1:6
Thread-0:6
Thread-0:7
Thread-1:8
Thread-0:9
Thread-1:10
Thread-0:11
Thread-1:12
Thread-0:13
Thread-1:14
Thread-0:15
Thread-1:16
Thread-0:17
Thread-1:18
Thread-0:19
Thread-1:20
Thread-0:21
Thread-1:22
Thread-0:23
Thread-1:24
Thread-0:25
Thread-1:26
Thread-0:27
Thread-1:28
Thread-0:29
Thread-1:30
Thread-0:31
Thread-1:32
Thread-0:33
Thread-1:34
Thread-0:35
Thread-1:36
Thread-0:37
Thread-1:38
Thread-0:39
Thread-1:40
Thread-0:41
Thread-1:42
Thread-0:43
Thread-1:44
Thread-0:45
Thread-1:46
Thread-0:47
Thread-1:48
Thread-0:49
在此例中,i是成员变量,两个线程都由同一个类构造,所以共享了同一个i,同时也可以观察到此类不是线程安全的,因为i++不是一个原子性操作。此例仅是为了说明成员变量会被多个线程共享,所以必须采取其他的机制保证线程安全性。
局部变量:
package deep;
public class LocalVariableThread implements Runnable {
@Override
public void run() {
int i = 0; // 每一个线程都会拥有自己的一份局部变量的拷贝,线程之间互不影响,所以会打印100个数字,0到49每个数字都是两遍
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + i++);
if (50 == i) {
break;
}
}
}
}
package deep;
public class Test {
public static void main(String[] args) {
LocalVariableThread localVariableThread = new LocalVariableThread();
Thread thread1 = new Thread(localVariableThread);
Thread thread2 = new Thread(localVariableThread);
thread1.start();
thread2.start();
}
}
运行结果:
Thread-0:0
Thread-1:0
Thread-0:1
Thread-1:1
Thread-0:2
Thread-1:2
Thread-0:3
Thread-1:3
Thread-0:4
Thread-1:4
Thread-0:5
Thread-1:5
Thread-0:6
Thread-1:6
Thread-0:7
Thread-1:7
Thread-0:8
Thread-0:9
Thread-1:8
Thread-0:10
Thread-1:9
Thread-0:11
Thread-1:10
Thread-1:11
Thread-1:12
Thread-1:13
Thread-0:12
Thread-1:14
Thread-0:13
Thread-1:15
Thread-0:14
Thread-1:16
Thread-0:15
Thread-1:17
Thread-0:16
Thread-1:18
Thread-0:17
Thread-1:19
Thread-0:18
Thread-1:20
Thread-0:19
Thread-1:21
Thread-0:20
Thread-1:22
Thread-1:23
Thread-1:24
Thread-1:25
Thread-1:26
Thread-1:27
Thread-1:28
Thread-1:29
Thread-1:30
Thread-1:31
Thread-1:32
Thread-1:33
Thread-0:21
Thread-1:34
Thread-1:35
Thread-0:22
Thread-1:36
Thread-0:23
Thread-0:24
Thread-1:37
Thread-0:25
Thread-1:38
Thread-0:26
Thread-1:39
Thread-0:27
Thread-1:40
Thread-0:28
Thread-1:41
Thread-0:29
Thread-1:42
Thread-0:30
Thread-1:43
Thread-0:31
Thread-1:44
Thread-0:32
Thread-1:45
Thread-0:33
Thread-1:46
Thread-0:34
Thread-1:47
Thread-0:35
Thread-1:48
Thread-0:36
Thread-1:49
Thread-0:37
Thread-0:38
Thread-0:39
Thread-0:40
Thread-0:41
Thread-0:42
Thread-0:43
Thread-0:44
Thread-0:45
Thread-0:46
Thread-0:47
Thread-0:48
Thread-0:49
如注释中所述,由于局部变量对于每一个线程来说都有自己的拷贝,所以各个线程之间不再共享同一个变量,输出结果为100个数字,实际上是两组,每组都是0到49的50个数字,并且两组数字之间随意地穿插在一起。
总结:
- 如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时,它们对该成员变量是彼此影响的,也就是说一个线程对成员变量的改变会影响到另一个线程。
- 如果一个变量是局部变量,那么每个线程都会有一个该局部变量的拷贝(即便是同一个对象中的方法的局部变量,也会对每一个线程有一个拷贝),一个线程对该局部变量的改变不会影响到其他线程。