我有以下代码:
public class A extends Thread{
static List<String> a = new ArrayList<String>();
private String name;
public A(String name)
{
this.name = name;
}
public void run() {
synchronized (A.class) {
a.add(this.name);
}
}
public static void main(String[] args) throws Exception{
for(int i=0;i<100;i++)
{
A s1 = new A("thread 1");
A s2 = new A("thread 2");
A s3 = new A("thread 3");
s1.start();
s2.start();
s3.start();
}
Thread.sleep(1000);
System.out.println("The message is " + a);
}
}
我得到的输出是:
The message is [thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3, thread 1, thread 2, thread 3]
从输出中我不认为我的线程并行运行!
我应该在run
方法中添加并发代码吗?
我在这里错过了什么吗?
答案 0 :(得分:8)
您的主题只运行 非常 短暂的时间段,因为run
几乎立即终止。所以可能,但不太可能,它们同时运行。线程在其run
方法返回时终止;不会重复调用run
方法或类似的方法。
当然,由于您在run
中执行的所有操作都在A.class
上同步,即使它们同时运行,也会阻止其他人在添加到共享列表时。
如果你想看到线程实际同时运行的效果,你需要让它们继续做某事(可能是run
中的某种循环,或者随机使用Thread.sleep
毫秒数,并删除同步(或播放同步以查看它如何影响事物)。但是,在执行此操作时,请在调用a.add
时保持同步(最好在a
而不是A.class
上同步),即使在其他地方没有同步时也是如此。 (或者将您的列表包装在Collections.synchronizedList
中。)
这是一个完整的示例,显示了实际上彼此重叠的线程:
import java.util.*;
public class ParallelExample extends Thread {
static List<String> a = new ArrayList<String>();
private String name;
public ParallelExample(String name) {
this.name = name;
}
public void run() {
// Un-synchronized, random delay, just to let the threads
// intermix.
try {
Thread.sleep((new Random()).nextInt(1000) + 500);
}
catch (Exception e) {
// For this example I'm ignoring the InterruptedException
}
// Now add the name after that random delay
synchronized(ParallelExample.class) {
a.add(this.name);
}
}
public static void main(String[] args) throws Exception {
ParallelExample threads[] = new ParallelExample[10];
// Start the threads
for (int i = 0; i < threads.length; ++i) {
threads[i] = new ParallelExample("thread " + i);
threads[i].start();
}
// Don't use sleep here, use join
try {
for (int i = 0; i < threads.length; ++i) {
threads[i].join();
}
}
catch (Exception e) {
// For this example I'm ignoring the InterruptedException
}
// Show results
System.out.println("The message is " + a);
}
}
示例运行:
$ java ParallelExample The message is [thread 4, thread 3, thread 9, thread 7, thread 6, thread 2, thread 5, thread 1, thread 8, thread 0]
答案 1 :(得分:0)
要查看差异线程,请尝试以下操作:
public void run() {
synchronized (A.class) {
Thread.sleep(10000);
a.add(this.name);
}
}
然后尝试以下方法:
public void run() {
Thread.sleep(10000);
synchronized (A.class) {
a.add(this.name);
}
}
两者都会产生大约相同的输出(根据时间的不同,它可能会有所不同),但是你会看到总运行时间的巨大差异。
在每种情况下,你产生3个线程,每个线程等待10秒然后返回。
在第一种情况下,尽管每个线程必须等待同步块才能进行处理 - 因此总运行时间大约为30秒。
在第二种情况下,总运行时间约为10秒。
这是串行和并行执行之间的区别。想象一下,10秒等待实际上是密集的,你可以看到线程如何加快速度。
这也说明了为什么正确的同步在线程中非常重要。不要这样做,你可以崩溃你的程序,破坏数据,以及各种其他的肮脏。做得太多,你可以删除线程的所有好处,甚至在某些情况下完全使你的程序陷入僵局。
另一方面,虽然在正确的情况下它可能非常强大,例如最近我正在重新处理大量图像,每次重新处理可能需要10秒到2分钟。
通过使用线程并向每个线程发送不同的Image,我能够使用CPU上的所有核心来进行处理。由于每个Image都是独立的,因此没有同步块来减慢速度。这导致了巨大的性能提升。
答案 2 :(得分:0)
避免同步阻止并使用非阻塞解决方案。
而不是使用:
static List<String> a = new ArrayList<String>();
// Now add the name after that random delay
synchronized(ParallelExample.class) {
a.add(this.name);
}
您可以使用以下内容:
private static Queue<String> queue = new ConcurrentLinkedQueue<String>();
// Now add the name after that random delay
queue.offer(this.name);