显示 Java 中 2 个线程同步的用法
Showing usage of Synchronization with 2 Threads in Java
我一直在寻找多线程教程和那些特定于同步的教程,但我无法实现我需要的东西。
它展示了我的程序中发生的同步。
基本上,我有一个 class 从另一个 class 继承了一些函数,这些函数需要同步以便两个线程不会同时修改对象(没有数据损坏)。
我之前实现的代码没有使用同步关键字,所以我可以设法看到数据损坏的发生。
EditOptionsMethods e1;
int threadNo;
public EditOptions() {
e1 = new BuildAuto();
run();
}
public void run() {
System.out.println("Thread running.");
switch (threadNo) {
case 0:
break;
case 1:
break;
}
}
public void setOptions(String optSetName1, String desiredOption1, String optSetName2, String desiredOption2) {
e1.s_Option(optSetName1, desiredOption1); //
e1.s_Option(optSetName2, desiredOption2);
}
s_Option 必须同步,这样两个线程都不会发生。
我首先将在没有同步的情况下使用它,然后我可以初始化一个循环(具有高索引量,假设为 1000,然后我用第一个线程添加,并用第二个线程减去)以查看发生的损坏为例。
但是我找不到显示这个的方法。
如果有人知道我如何实现它,那就太棒了。
首先创建一个将容纳线程的结构:
List<Thread> threads = new ArrayList<>();
然后对其进行初始化,并将工作分配给线程:
int total_threads = 2;
for(int i = 0; i < total_threads; i++){
Thread thread = new Thread(() -> {
// the work to be done by the threads
});
threads.add(thread);
}
运行 个线程:
threads.forEach(Thread::start);
最后,等待线程完成它们的工作:
threads.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
以运行宁为例:
import java.util.*;
public class SomeClass {
private int x;
public void addX(int y){ x = x + y;}
public static void main(String[] args) {
SomeClass example = new SomeClass();
List<Thread> threads = new ArrayList<>();
int total_threads = 2;
for(int i = 1; i < total_threads + 1; i++){
final int threadID = i;
Thread thread = new Thread(() -> {
for(int j = 0; j < 1000; j++ )
example.addX((threadID % 2 == 0) ? -threadID : threadID);
});
threads.add(thread);
}
threads.forEach(Thread::start);
threads.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(example.x);
}
}
现在尝试 运行 上面的示例,同步和不同步线程完成的工作:
Thread thread = new Thread(() -> {
for(int j = 0; j < 1000; j++ )
example.addX((threadID % 2 == 0) ? -threadID : threadID);
});
对比:
Thread thread = new Thread(() -> {
synchronized(example){ // <-- adding synchronization
for(int j = 0; j < 1000; j++ )
example.addX((threadID % 2 == 0) ? -threadID : threadID);
}
});
对于使用同步的版本,您可以 运行 任意多次代码,输出将始终为 -1000
(使用 2 个线程)。但是,对于没有同步的版本,由于在更新变量 x
.
期间发生竞争条件,输出将是不确定的
您可以选择更高的抽象,而不是直接使用 Thread
class,即 executors:
public class SomeClass2 {
private int x;
public void addX(int y){x = x + y;}
public static void main(String[] args) {
SomeClass2 example = new SomeClass2();
int total_threads = 2;
ExecutorService pool = Executors.newFixedThreadPool(total_threads);
pool.execute(() -> {
synchronized (example) {
parallel_task(example, -2);
}
});
pool.execute(() -> {
synchronized (example) {
parallel_task(example, 1);
}
});
pool.shutdown();
try { pool.awaitTermination(1, TimeUnit.MINUTES);}
catch (InterruptedException e) {e.printStackTrace();}
System.out.println(example.x);
}
private static void parallel_task(SomeClass2 example, int i) {
thread_sleep();
for (int j = 0; j < 1000; j++)
example.addX(i);
}
private static void thread_sleep() {
try { Thread.sleep(1000); }
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我添加了 thread_sleep()
以确保两个并行任务不会被线程池中的同一个线程拾取。
我一直在寻找多线程教程和那些特定于同步的教程,但我无法实现我需要的东西。
它展示了我的程序中发生的同步。
基本上,我有一个 class 从另一个 class 继承了一些函数,这些函数需要同步以便两个线程不会同时修改对象(没有数据损坏)。
我之前实现的代码没有使用同步关键字,所以我可以设法看到数据损坏的发生。
EditOptionsMethods e1;
int threadNo;
public EditOptions() {
e1 = new BuildAuto();
run();
}
public void run() {
System.out.println("Thread running.");
switch (threadNo) {
case 0:
break;
case 1:
break;
}
}
public void setOptions(String optSetName1, String desiredOption1, String optSetName2, String desiredOption2) {
e1.s_Option(optSetName1, desiredOption1); //
e1.s_Option(optSetName2, desiredOption2);
}
s_Option 必须同步,这样两个线程都不会发生。 我首先将在没有同步的情况下使用它,然后我可以初始化一个循环(具有高索引量,假设为 1000,然后我用第一个线程添加,并用第二个线程减去)以查看发生的损坏为例。
但是我找不到显示这个的方法。
如果有人知道我如何实现它,那就太棒了。
首先创建一个将容纳线程的结构:
List<Thread> threads = new ArrayList<>();
然后对其进行初始化,并将工作分配给线程:
int total_threads = 2;
for(int i = 0; i < total_threads; i++){
Thread thread = new Thread(() -> {
// the work to be done by the threads
});
threads.add(thread);
}
运行 个线程:
threads.forEach(Thread::start);
最后,等待线程完成它们的工作:
threads.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
以运行宁为例:
import java.util.*;
public class SomeClass {
private int x;
public void addX(int y){ x = x + y;}
public static void main(String[] args) {
SomeClass example = new SomeClass();
List<Thread> threads = new ArrayList<>();
int total_threads = 2;
for(int i = 1; i < total_threads + 1; i++){
final int threadID = i;
Thread thread = new Thread(() -> {
for(int j = 0; j < 1000; j++ )
example.addX((threadID % 2 == 0) ? -threadID : threadID);
});
threads.add(thread);
}
threads.forEach(Thread::start);
threads.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(example.x);
}
}
现在尝试 运行 上面的示例,同步和不同步线程完成的工作:
Thread thread = new Thread(() -> {
for(int j = 0; j < 1000; j++ )
example.addX((threadID % 2 == 0) ? -threadID : threadID);
});
对比:
Thread thread = new Thread(() -> {
synchronized(example){ // <-- adding synchronization
for(int j = 0; j < 1000; j++ )
example.addX((threadID % 2 == 0) ? -threadID : threadID);
}
});
对于使用同步的版本,您可以 运行 任意多次代码,输出将始终为 -1000
(使用 2 个线程)。但是,对于没有同步的版本,由于在更新变量 x
.
您可以选择更高的抽象,而不是直接使用 Thread
class,即 executors:
public class SomeClass2 {
private int x;
public void addX(int y){x = x + y;}
public static void main(String[] args) {
SomeClass2 example = new SomeClass2();
int total_threads = 2;
ExecutorService pool = Executors.newFixedThreadPool(total_threads);
pool.execute(() -> {
synchronized (example) {
parallel_task(example, -2);
}
});
pool.execute(() -> {
synchronized (example) {
parallel_task(example, 1);
}
});
pool.shutdown();
try { pool.awaitTermination(1, TimeUnit.MINUTES);}
catch (InterruptedException e) {e.printStackTrace();}
System.out.println(example.x);
}
private static void parallel_task(SomeClass2 example, int i) {
thread_sleep();
for (int j = 0; j < 1000; j++)
example.addX(i);
}
private static void thread_sleep() {
try { Thread.sleep(1000); }
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我添加了 thread_sleep()
以确保两个并行任务不会被线程池中的同一个线程拾取。