Viv*_*vek 7 java multithreading
我是多线程的新手,我得到了一个问题,使用Java中的10个线程以低于约束打印1到100.
线程t1
应该打印:
1,11,21,31,...... 91
t2
应该打印:
2,12,22,32,...... 92
同样
t10
应该打印:
10,20,30,...... 100
最终的输出应该是
1 2 3 .. 100
我试过了,但它在所有10个线程中抛出以下异常:
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at thread.run(MyThread.java:58)
at java.lang.Thread.run(Unknown Source)
Run Code Online (Sandbox Code Playgroud)
请让我知道如何解决这个问题.
public class MyThread {
/**
* @param args
*/
public static void main(String[] args) {
thread.setSequence();
for(int i = 1; i <= 10; i++) {
Thread t = new Thread(new thread(i));
t.setName(i + "");
t.start();
}
}
}
class thread implements Runnable {
private static HashMap< String, String> sequence = new HashMap<String, String>();
public static final Object lock = new Object();
public static String turn = "1";
private int startValue = 0;
private AtomicInteger counter = new AtomicInteger(1);
public thread(int startValue){
this.startValue = startValue;
}
@Override
public void run() {
while (!counter.equals(10)){
synchronized (lock) {
if(Thread.currentThread().getName().equals(turn)){
System.out.print(startValue + " ");
startValue += 10;
counter.incrementAndGet();
turn = getNextTurn(turn);
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
}
}
}
public static void setSequence(){
for (int i = 1; i <= 10; i++)
if (i == 10)
sequence.put(i + "", 1 + "");
else
sequence.put(i + "", (i + 1) + "");
}
public static String getNextTurn(String currentTurn){
return sequence.get(currentTurn);
}
}
Run Code Online (Sandbox Code Playgroud)
最简单的方法是有一个volatile变量,每个线程从中读入并根据轮到它进行更新,否则它只会等到轮到他.当counter
等于100
你时,通过打破外部循环来停止所有线程运行.
class MyRunnable implements Runnable {
private static final int LIMIT = 20;
private static volatile int counter = 0;
private int id;
public MyRunnable(int id) {
this.id = id;
}
@Override
public void run() {
outer:
while(counter < LIMIT) {
while (counter % NB_THREADS != id) {
if(counter == LIMIT) break outer;
}
System.out.println("Thread "+Thread.currentThread().getName()+ " printed " + counter);
counter += 1;
}
}
}
Run Code Online (Sandbox Code Playgroud)
给定20和10个线程的LIMIT,它输出:
Thread 0 printed 0
Thread 1 printed 1
Thread 2 printed 2
Thread 3 printed 3
Thread 4 printed 4
Thread 5 printed 5
Thread 6 printed 6
Thread 7 printed 7
Thread 8 printed 8
Thread 9 printed 9
Thread 0 printed 10
Thread 1 printed 11
Thread 2 printed 12
Thread 3 printed 13
Thread 4 printed 14
Thread 5 printed 15
Thread 6 printed 16
Thread 7 printed 17
Thread 8 printed 18
Thread 9 printed 19
Run Code Online (Sandbox Code Playgroud)
当然,这是多线程的一个非常糟糕的用法,因为每个线程等待轮到打印并递增计数器.
当线程可以在相对长时间的窗口中独立工作时,多线程工作得很好,然后在需要时可能偶尔会遇到比较或组合它们的结果.
例如,在fork-join模型中,每个线程独立完成其任务,然后合并它们的结果以产生最终结果,例如在合并排序中.但是这假设任务可以很容易地并行化为独立的子任务,这不是这里的情况,因为你的最终输出应该是连续的数字.
所以这里一个简单的循环在很大程度上会更有效,但我可以理解它是出于学习目的.
小智 5
下面是这个问题的解决方案。当前线程获取锁,我们决定该线程是否有资格执行(在此处打印数字)。如果是,则执行操作并通知所有线程他们现在可以尝试。否则等待其他线程通知它。
public class MyThread extends Thread{
//define the Total No.Of Threads needed
public static final int TOTAL_THREADS = 10;
public final static Object obj = new Object();
int threadNo;
static volatile int counter = 1;
public MyThread(int threadNo){
this.threadNo= threadNo;
}
@Override
public void run(){
//in a synchronized block to acquire lock
synchronized (obj) {
while(counter<=100){
/*
* counter==threadNo => To print the initial numbers till TOTAL_THREADS
* counter%TOTAL_THREADS == threadNo => e.g 11%10 = 1 -> 1 will print this, 12%10 = 2 ..
* (counter%TOTAL_THREADS == 0) && (TOTAL_THREADS == threadNo) => 10%10 will be 0,
* and this must be printed by 10 th thread only, ie the highest thread.
*/
if(counter == threadNo || (counter%TOTAL_THREADS == threadNo) ||
((counter%TOTAL_THREADS == 0) && (TOTAL_THREADS == threadNo))){
//Display the output as desired
System.out.println(this.threadNo+" printing"+" "+counter++);
//notify
obj.notifyAll();
}else{
//current thread not eligible for printing the current counter value, so wait till its notified
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main (String args[]) {
/*
* Creating as many threads as needed.
*/
for(int i = 1; i<=TOTAL_THREADS;i++){
MyThread th = new MyThread(i);
th.start();
}
}
Run Code Online (Sandbox Code Playgroud)
}
输出将是
1 打印 1,
2 打印 2,
3 打印 3,
4 打印 4,
5 打印 5,
6 打印 6,
7 打印 7,
8 打印 8,
9 打印 9,
10 打印 10,
1 打印 11,
2 打印12,
3 印刷 13,
4 印刷 14,
...
7 印刷 97,
8 印刷 98,
9 印刷 99,
10 印刷 100
Avi*_*iad -1
简单的做法就是为所有人保留公共资源。持有一个列表,每个线程都会插入到列表中,最后你可以排序和打印。如果你想让他们按照你的订单做,它不会很有效,因为你不需要 10 个线程来完成它..
这样速度会更快,并且会使用 10 个线程来完成一些工作,但是当每个人都完成后,你仍然需要做一些工作