用信号量是一个基本思路,不过具体要遇到的同步和协作问题还是很多的。“启动线程时,加1,线程停止时,减1”,基本方法是这样。 但线程启动和停止时,不应该由该线程本身去操作信号量,而应该由一个调度线程(如main线程)来在适当的时候执行。 不然就会出现2楼所预计的那种情况。4楼的方法应该可行,但让“主线程循环判断信号量的值”,效率不高。5楼的方法是不行的,join()会让线程一个一个地串行执行,失去了并发的意义。其实,可以让调度线程(如main线程)在信号量为5的时候,wait(),这样,新的线程就暂时不能启动。 在每个线程结束的时候,信号量减1后,判断信号量的值,如果信号量为0,则让调度线程notify(),启动下面的5个。这样依次循环,直到所有线程执行完毕。我根据自己的思路实现的代码如下:// ThreadsRunner.java/* * run threads five by five */ public class ThreadsRunner extends Thread {
private SingleThread[] threads; private int threadsRunning, threadsLeft;
public ThreadsRunner(Runnable[] threadsToRun) { threads = new SingleThread[threadsToRun.length]; for (int i = 0; i < threads.length; i++) threads[i] = new SingleThread(threadsToRun[i]); threadsLeft = threads.length; }
public void run() { for (int i = 0; i < threads.length; i++) runAThread(threads[i]); }
private synchronized void threadDone() { threadsRunning--; if (threadsRunning == 0) { if (threadsLeft > 0) System.out.println("5 have done. Now running next " + (threadsLeft<5?threadsLeft:5) + "..."); else System.out.println("All have done."); notify(); } }} 该类用一个Runnable数组来构造,这样就可以运行任意多个任意线程。测试程序可以如下:// ThreadsRunnerTest.javapublic class ThreadsRunnerTest { public static void main(String[] args) { Runnable[] threads = new Runnable[12]; for (int i = 0; i < threads.length; i++) threads[i] = new Runnable() { public void run() { for (int i = 0; i < 100000; i++) new String("Just a string."); } }; new ThreadsRunner(threads).start(); } }
to Dan1980:你把事情想复杂了,我在 5 楼提的方法是可以的。请试着运行一下这段代码: import java.util.Random;public class TestMultiThread extends Thread { public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + " 开始测试..."); TestMultiThread t1 = new TestMultiThread(); TestMultiThread t2 = new TestMultiThread(); TestMultiThread t3 = new TestMultiThread(); TestMultiThread t4 = new TestMultiThread(); TestMultiThread t5 = new TestMultiThread(); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); try { t1.join(); t2.join(); t3.join(); t4.join(); t5.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 测试结束."); } @Override public void run() { System.out.println(Thread.currentThread().getName() + " 线程启动."); for (int i=0; i<10; i++) { System.out.println(Thread.currentThread().getName() + ": " + i); try { Thread.sleep(new Random().nextInt(3000) + 500); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " 线程结束."); }}
启动线程时,加1
线程停止时,减1判断从5减到0, 则再启动5个!
但线程启动和停止时,不应该由该线程本身去操作信号量,而应该由一个调度线程(如main线程)来在适当的时候执行。
不然就会出现2楼所预计的那种情况。4楼的方法应该可行,但让“主线程循环判断信号量的值”,效率不高。5楼的方法是不行的,join()会让线程一个一个地串行执行,失去了并发的意义。其实,可以让调度线程(如main线程)在信号量为5的时候,wait(),这样,新的线程就暂时不能启动。
在每个线程结束的时候,信号量减1后,判断信号量的值,如果信号量为0,则让调度线程notify(),启动下面的5个。这样依次循环,直到所有线程执行完毕。我根据自己的思路实现的代码如下:// ThreadsRunner.java/*
* run threads five by five
*/
public class ThreadsRunner extends Thread {
private SingleThread[] threads;
private int threadsRunning, threadsLeft;
private class SingleThread extends Thread {
SingleThread(Runnable r) {
super(r);
}
public void run() {
System.out.println(this.getName() + "starts.");
super.run();
System.out.println(this.getName() + "ends.");
threadDone();
} }
public ThreadsRunner(Runnable[] threadsToRun) {
threads = new SingleThread[threadsToRun.length];
for (int i = 0; i < threads.length; i++)
threads[i] = new SingleThread(threadsToRun[i]);
threadsLeft = threads.length;
}
public void run() {
for (int i = 0; i < threads.length; i++)
runAThread(threads[i]);
}
private synchronized void runAThread(SingleThread t) {
t.start();
threadsRunning++;
threadsLeft--;
if (threadsRunning == 5)
try {
wait();
} catch (InterruptedException ie) {
System.out.println("runner interrupted.");
}
}
private synchronized void threadDone() {
threadsRunning--;
if (threadsRunning == 0) {
if (threadsLeft > 0)
System.out.println("5 have done. Now running next " + (threadsLeft<5?threadsLeft:5) + "...");
else
System.out.println("All have done.");
notify();
}
}} 该类用一个Runnable数组来构造,这样就可以运行任意多个任意线程。测试程序可以如下:// ThreadsRunnerTest.javapublic class ThreadsRunnerTest {
public static void main(String[] args) {
Runnable[] threads = new Runnable[12];
for (int i = 0; i < threads.length; i++)
threads[i] = new Runnable() {
public void run() {
for (int i = 0; i < 100000; i++)
new String("Just a string.");
}
};
new ThreadsRunner(threads).start();
}
}
import java.util.Random;public class TestMultiThread extends Thread { public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " 开始测试...");
TestMultiThread t1 = new TestMultiThread();
TestMultiThread t2 = new TestMultiThread();
TestMultiThread t3 = new TestMultiThread();
TestMultiThread t4 = new TestMultiThread();
TestMultiThread t5 = new TestMultiThread();
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 测试结束.");
} @Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 线程启动.");
for (int i=0; i<10; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(new Random().nextInt(3000) + 500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 线程结束.");
}}