多线程
Multi threading
我有一个关于多线程的想法,但我从未付诸实践。所以,当我看到我的应用程序在工作时......我没有看到任何 class 扩展线程创建 Thread
。因此,当 2 个对象试图同时访问一个变量时,使用 synchronized
关键字。我们使用 synchronized 来避免冲突。
示例:
public class Test {
private static int count = 0;
public static synchronized void incrementCount() {
count++;
}
}
如果测试 class 被对象使用,那么将 synchronized
添加到 incrementcount()
是有意义的。但是当你不扩展 Thread
或 Runnable
那么写 synchronized
.
有什么用
Synchronized 不适用于线程或 Runnable,它用于被多个线程访问的数据结构,以确保每个线程以不破坏其数据的方式访问它们。你自己的例子是一个基本的例子,其中计数以一种非线程安全的方式增加(using ++, see this question),所以它需要锁定以确保一次只有一个线程可以增加它。
如果有其他代码访问计数,它也需要同步,以便它可以看到计数的更新。如果您所做的只是递增计数器,那么使用 class 更有意义,例如 java.util.concurrent.atomic.AtomicInteger
,并且您可以完全不使用 synchronized 关键字。
为了使使用 synchronized 有意义,它确实假设有多个线程。即使您自己的代码不创建新线程,也可能存在多个线程调用您的代码的情况(例如在 servlet 容器中,容器管理一个线程池并为每个传入请求分配一个线程)。
i++
,看似单条指令,其实是多条指令:
- 将临时变量设置为
1+i
。
- 设置变量
i
为临时变量
但是,假设执行i++
的线程在步骤1
之后被中断,中断线程也调用i++
。然后,会发生这样的事情:
(假设i=1
)
- 原线程: 将临时变量 1 设置为
1+i
,或 2
。
- 中断线程: 将临时变量 2 设置为
i+1
,也 2
- 中断线程: 将
i
设置为临时变量2。现在i=2
- 原帖: 将
i
设置为临时变量1。现在i=2
问题是如果i++
调用了两次,应该是3
,而不是2
。
A synchronized void
将锁定变量 i
直到整个 void
完成执行。例如:
- 原线程: 将临时变量 1 设置为
1+i
,或 2
。锁定变量 i
.
- 中断线程: 尝试将临时变量 2 设置为
i+1
,但由于变量 i
的锁定而等待
- 原帖: 将
i
设置为临时变量1。现在i=2
。变量 i
现已解锁。
- 中断线程: "notices"
i
已解锁,因此将临时变量2设置为 i+1
即 3
.
- 中断线程: 将
i
设置为 3
,这是预期的行为。
synchronized void
s 基本上临时锁定变量以避免混淆程序的执行。
A class 不需要 extend Thread
或 implements Runnable
将其方法标记为同步以防止多线程访问
您的 class 可能是某个其他线程 class 的参数,并且该线程 class 可能有多个实例。为了提供强一致性的数据,您必须保护代码和数据的关键部分。
只需更改您的代码示例,如下所示。
我在对象级别而不是 class 级别演示“synchronized
”(static synchronized
)
class Test {
private int count = 0;
public void incrementCount() {
count++;
System.out.println("Count:"+count);
}
}
class MyRunnable implements Runnable{
private Test test = null;
public MyRunnable(Test t){
this.test = t;
}
public void run(){
test.incrementCount();
}
}
public class SynchronizedDemo{
public static void main(String args[]){
Test t = new Test();
for ( int i=0; i<10; i++){
new Thread(new MyRunnable(t)).start();
}
}
}
您的 class Test
已作为参数传递给线程 MyRunnable
。现在您已经创建了多个线程实例。如果没有 synchronized
关键字,输出将不可预测,如下所示。
java SynchronizedDemo
Count:2
Count:3
Count:2
Count:7
Count:6
Count:5
Count:4
Count:10
Count:9
Count:8
如果我改变
public void incrementCount() {
到
public synchronized void incrementCount() {
输出为:
Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10
换句话说,您已将方法设为 static synchronized
。 That means lock is maintained at class level instead of object level.
查看 oracle 文档 page 以获得更好的理解。
缺少“static synchronized
”的代码演示
class Test {
private static int count = 0;
public static void incrementCount() {
count++;
System.out.println("Count:"+count);
}
}
class MyRunnable implements Runnable{
private Test test = null;
public MyRunnable(Test t){
this.test = t;
}
public void run(){
test.incrementCount();
}
}
public class SynchronizedDemo{
public static void main(String args[]){
for ( int i=0; i<10; i++){
Test t = new Test();
new Thread(new MyRunnable(t)).start();
}
}
}
输出:
Count:5
Count:4
Count:3
Count:2
Count:10
Count:9
Count:8
Count:7
Count:6
制作后
public static void incrementCount() {
到
ppublic static synchronized void incrementCount() {
输出:
Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10
在此示例中,与之前不同,我们创建了 10 个不同的 Test
个实例。
我有一个关于多线程的想法,但我从未付诸实践。所以,当我看到我的应用程序在工作时......我没有看到任何 class 扩展线程创建 Thread
。因此,当 2 个对象试图同时访问一个变量时,使用 synchronized
关键字。我们使用 synchronized 来避免冲突。
示例:
public class Test {
private static int count = 0;
public static synchronized void incrementCount() {
count++;
}
}
如果测试 class 被对象使用,那么将 synchronized
添加到 incrementcount()
是有意义的。但是当你不扩展 Thread
或 Runnable
那么写 synchronized
.
Synchronized 不适用于线程或 Runnable,它用于被多个线程访问的数据结构,以确保每个线程以不破坏其数据的方式访问它们。你自己的例子是一个基本的例子,其中计数以一种非线程安全的方式增加(using ++, see this question),所以它需要锁定以确保一次只有一个线程可以增加它。
如果有其他代码访问计数,它也需要同步,以便它可以看到计数的更新。如果您所做的只是递增计数器,那么使用 class 更有意义,例如 java.util.concurrent.atomic.AtomicInteger
,并且您可以完全不使用 synchronized 关键字。
为了使使用 synchronized 有意义,它确实假设有多个线程。即使您自己的代码不创建新线程,也可能存在多个线程调用您的代码的情况(例如在 servlet 容器中,容器管理一个线程池并为每个传入请求分配一个线程)。
i++
,看似单条指令,其实是多条指令:
- 将临时变量设置为
1+i
。 - 设置变量
i
为临时变量
但是,假设执行i++
的线程在步骤1
之后被中断,中断线程也调用i++
。然后,会发生这样的事情:
(假设i=1
)
- 原线程: 将临时变量 1 设置为
1+i
,或2
。 - 中断线程: 将临时变量 2 设置为
i+1
,也2
- 中断线程: 将
i
设置为临时变量2。现在i=2
- 原帖: 将
i
设置为临时变量1。现在i=2
问题是如果i++
调用了两次,应该是3
,而不是2
。
A synchronized void
将锁定变量 i
直到整个 void
完成执行。例如:
- 原线程: 将临时变量 1 设置为
1+i
,或2
。锁定变量i
. - 中断线程: 尝试将临时变量 2 设置为
i+1
,但由于变量i
的锁定而等待
- 原帖: 将
i
设置为临时变量1。现在i=2
。变量i
现已解锁。 - 中断线程: "notices"
i
已解锁,因此将临时变量2设置为i+1
即3
. - 中断线程: 将
i
设置为3
,这是预期的行为。
synchronized void
s 基本上临时锁定变量以避免混淆程序的执行。
A class 不需要 extend Thread
或 implements Runnable
将其方法标记为同步以防止多线程访问
您的 class 可能是某个其他线程 class 的参数,并且该线程 class 可能有多个实例。为了提供强一致性的数据,您必须保护代码和数据的关键部分。
只需更改您的代码示例,如下所示。
我在对象级别而不是 class 级别演示“synchronized
”(static synchronized
)
class Test {
private int count = 0;
public void incrementCount() {
count++;
System.out.println("Count:"+count);
}
}
class MyRunnable implements Runnable{
private Test test = null;
public MyRunnable(Test t){
this.test = t;
}
public void run(){
test.incrementCount();
}
}
public class SynchronizedDemo{
public static void main(String args[]){
Test t = new Test();
for ( int i=0; i<10; i++){
new Thread(new MyRunnable(t)).start();
}
}
}
您的 class Test
已作为参数传递给线程 MyRunnable
。现在您已经创建了多个线程实例。如果没有 synchronized
关键字,输出将不可预测,如下所示。
java SynchronizedDemo
Count:2
Count:3
Count:2
Count:7
Count:6
Count:5
Count:4
Count:10
Count:9
Count:8
如果我改变
public void incrementCount() {
到
public synchronized void incrementCount() {
输出为:
Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10
换句话说,您已将方法设为 static synchronized
。 That means lock is maintained at class level instead of object level.
查看 oracle 文档 page 以获得更好的理解。
缺少“static synchronized
”的代码演示
class Test {
private static int count = 0;
public static void incrementCount() {
count++;
System.out.println("Count:"+count);
}
}
class MyRunnable implements Runnable{
private Test test = null;
public MyRunnable(Test t){
this.test = t;
}
public void run(){
test.incrementCount();
}
}
public class SynchronizedDemo{
public static void main(String args[]){
for ( int i=0; i<10; i++){
Test t = new Test();
new Thread(new MyRunnable(t)).start();
}
}
}
输出:
Count:5
Count:4
Count:3
Count:2
Count:10
Count:9
Count:8
Count:7
Count:6
制作后
public static void incrementCount() {
到
ppublic static synchronized void incrementCount() {
输出:
Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10
在此示例中,与之前不同,我们创建了 10 个不同的 Test
个实例。