我一直在寻找多线程教程以及与同步有关的教程,但是我无法实现我需要的东西。
它展示了我的程序中正在发生的同步。
基本上,我有一个从其他类继承一些功能的类,这些功能需要同步,以便两个线程不会同时修改一个对象(不会破坏数据)。
之前,我没有使用syncnize关键字就实现了代码,因此我可以设法查看发生的数据损坏情况。
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
直接使用类之外,你还可以选择更高的抽象,即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()
以确保两个并行任务不会被线程池中的同一线程拾取。