我是多线程的新手,我得到一个问题,使用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)
请告诉我如何解决这个问题。
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);
}
}
答案 0 :(得分:6)
最简单的方法是拥有一个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;
}
}
}
如果LIMIT为20和10个线程,则输出:
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
当然,这是多线程的一个非常糟糕的用法,因为每个线程轮流打印并递增计数器。
当线程可以在相对长时间的窗口中独立工作时,多线程很有效,然后可能偶尔会遇到比较或组合它们的结果(如果需要)。
例如,在fork-join模型中,每个线程独立完成其任务,然后合并它们的结果以产生最终结果,例如在合并排序中。但是这假设任务可以很容易地并行化为独立的子任务,这不是这里的情况,因为你的最终输出应该是连续的数字。
所以这里一个简单的循环会更有效率,但我可以理解它是出于学习目的。
答案 1 :(得分:3)
希望这会有所帮助=)花了我一个小时的时间来完成它。
package com.xxxx.simpleapp;
import java.util.ArrayList;
import java.util.List;
public class TenThreads {
public int currentTaskValue = 1;
public static void main(String[] args) {
TenThreads monitor = new TenThreads();
List<ModThread> list = new ArrayList();
for (int i = 0; i < 10; i++) {
ModThread modThread = new ModThread(i, monitor);
list.add(modThread);
}
for (ModThread a : list) {
a.start();
}
}
}
class ModThread extends Thread {
private int modValue;
private TenThreads monitor;
public ModThread(int modValue, TenThreads monitor) {
this.modValue = modValue;
this.monitor = monitor;
}
@Override
public void run() {
synchronized (monitor) {
try {
while (true) {
while (monitor.currentTaskValue % 10 != modValue) {
monitor.wait();
}
if (monitor.currentTaskValue == 101) {
break;
}
System.out.println(Thread.currentThread().getName() + " : "
+ monitor.currentTaskValue + " ,");
monitor.currentTaskValue = monitor.currentTaskValue + 1;
monitor.notifyAll();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
输出
Thread-1 : 1 ,
Thread-2 : 2 ,
Thread-3 : 3 ,
Thread-4 : 4 ,
Thread-5 : 5 ,
Thread-6 : 6 ,
Thread-7 : 7 ,
Thread-8 : 8 ,
Thread-9 : 9 ,
......
.....
...
Thread-4 : 94 ,
Thread-5 : 95 ,
Thread-6 : 96 ,
Thread-7 : 97 ,
Thread-8 : 98 ,
Thread-9 : 99 ,
Thread-0 : 100 ,
有意遗漏文档供您查明,也有小错误!
答案 2 :(得分:2)
由于调用wait
而不是正确的对象而引发错误。应该在获取锁定的对象上调用wait()
,synchronized
关键字隐含的对象。
答案 3 :(得分:2)
这是问题的解决方案。当前线程获取锁定,我们决定线程是否有资格执行(在此处打印数字)。如果是,则执行操作并通知所有线程,他们现在可以尝试。否则等待其他线程通知。
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();
}
}
}
输出将是
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
答案 4 :(得分:1)
嗯,我没有代码......但透视似乎是 每个递增都有100个任务要执行 按1计数。 所以可能有一个说10个线程的ThreadPool和这些 线程正在递增共享计数值... 只需要考虑的是线程池工作线程 必须一个接一个地顺序执行他们的任务 并且必须维护10的线程序列......
答案 5 :(得分:0)
public class BigSequence {
public static void main(String[] args) {
BigPrintNum p = new BigPrintNum();
int max = 20;
int no_threads = 11;
for(int i=0;i<no_threads;i++){
boolean b[] = new boolean[no_threads];
b[i] = true;
Thread t = new Thread(new BigPrint(p, max, b,no_threads));
t.start();
}
}
}
class BigPrint implements Runnable {
int num=0;
BigPrintNum p;
int max;
int no_threads;
boolean b[];
public BigPrint(BigPrintNum p,int max,boolean b[],int no_threads){
this.p = p;
this.max = max;
this.b = b;
this.no_threads = no_threads;
}
@Override
public void run() {
int n = 0;
for(int i=0;i<no_threads;i++){
if(b[i] == true){
n = i;
num = i;
}
}
while(num<=max){
p.print(num, n, no_threads);
num += no_threads;
}
}
}
class BigPrintNum {
int turn = 0;
public synchronized void print(int n,int i,int no_threads){
while(this.turn != i){
try{
wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println(i + "th seq = " + n);
this.turn = (i+1)%no_threads;
notifyAll();
}
}
它是一个通用的,我们可以使用任意数量的线程并使用任何最大值。
答案 6 :(得分:0)
public class ThreadSequence
{
public static int totalThread;
public static void main(String[] args)
{
MyLock myLock = new MyLock();
totalThread = 10;
for(int i=1;i<=totalThread;i++)
{
MyThread myThread = new MyThread(i,myLock);
myThread.start();
}
}
}
class MyLock
{
public int counter = 0;
}
MyThread Class
class MyThread extends Thread{
public MyLock lock;
public int no;
public MyThread(int no,MyLock lock)
{
super("My Thread No "+no);
this.no = no;
this.lock = lock;
}
public void run()
{
synchronized (lock)
{
while(true)
{
while(lock.counter%ThreadSequence.totalThread !=(this.no-1))
{
try
{
if(lock.counter > 99)
{
break;
}
lock.wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
if(lock.counter > 99)
{
break;
}
System.out.println("Current Thread "+Thread.currentThread().currentThread()+" --- Current Count "+(lock.counter+1));
lock.counter = lock.counter +1 ;
lock.notifyAll();
}
}
}
}
答案 7 :(得分:0)
解决这个问题的一种简单方法是在可运行类中使用下面的状态
private final int index;
private final AtomicInteger atomicInteger;
private final CyclicBarrier cyclicBarrier;
index - 负责条件验证,即该线程应该打印哪个数字。 atomicInteger - 在当前编号的所有线程之间共享。 循环屏障 - 使所有线程等待单元,每个线程完成一个循环/迭代。
代码示例:
public class PrintSequence {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
final AtomicInteger atomicInteger = new AtomicInteger(1);
final CyclicBarrier cyclicBarrier = new CyclicBarrier(10, ()-> {
System.out.println("a cycle done");
});
IntStream.rangeClosed(0, 9)
.boxed()
.map(i -> new PrintSequenceTask(i, atomicInteger, cyclicBarrier))
.map(p -> executorService.submit(p))
.collect(Collectors.toList());
executorService.shutdown();
}
}
class PrintSequenceTask implements Runnable {
private final int index;
private final AtomicInteger atomicInteger;
private final CyclicBarrier cyclicBarrier;
PrintSequenceTask(int index, AtomicInteger atomicInteger, CyclicBarrier cyclicBarrier) {
this.index = index;
this.atomicInteger = atomicInteger;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run(){
for(int i=1; i<10;i++){
while (((atomicInteger.get()-index-1)%10 != 0)){}
System.out.println(Thread.currentThread().getName()+" "+(atomicInteger.get()));
atomicInteger.getAndIncrement();
await();
}
}
public void await(){
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
答案 8 :(得分:-1)
简单的做法是为所有人保留公共资源。 保持一个List,每个线程都会插入到列表中,最后你可以排序和打印.. 如果您希望他们按照您的订单执行此操作,那么它将不会非常有效,因为您不需要10个线程来执行此操作。
这样会更快,并且会使用10个线程来完成一些工作,但是当每个人都完成后你仍然需要做一些工作
答案 9 :(得分:-1)
public class PrintNumbersbyThreads implements Runnable {
private int i;
public PrintNumbersbyThreads(int i) {
this.i = i;
}
public static void main(String[] args) {
PrintNumbersbyThreads p = new PrintNumbersbyThreads(1);
PrintNumbersbyThreads p2 = new PrintNumbersbyThreads(2);
PrintNumbersbyThreads p3 = new PrintNumbersbyThreads(3);
Thread t1 = new Thread(p, "t1");
Thread t2 = new Thread(p2, "t2");
Thread t3 = new Thread(p3, "t3");
t1.start();
try {
t1.join();
t2.start();
t2.join();
t3.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
System.out.println("\n" + Thread.currentThread().getName() + " prints ");
for (int j = 0; j < 10; j++) {
System.out.print(i + " ");
i = i + 10;
}
}
}
书面示例代码3线程和输出
t1
打印:
1 11 21 31 41 51 61 71 81 91
t2
打印:
2 12 22 32 42 52 62 72 82 92
t3
打印:
3 13 23 33 43 53 63 73 83 93
希望这是你在找什么?