在java中使用10个线程打印1到100

时间:2015-05-04 07:30:22

标签: java multithreading

我是多线程的新手,我得到一个问题,使用Java中的10个线程以低于约束打印1到100。

  1. 应打印线程t1

      

    1,11,21,31,...... 91

    t2应打印:

      

    2,12,22,32,... 92

    同样

    t10应打印:

      

    10,20,30,...... 100

  2. 最终输出应为

      

    1 2 3 .. 100

  3. 我试过了,但它在所有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);
        }
    }
    

10 个答案:

答案 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

希望这是你在找什么?