2013-03-10 36 views
1

我想創建一個實現,其中多個線程打印序列的備用值。所以這裏thread1會打印1,4,7 thread2會打印2,5,8 thread3會打印3,6,9。我正在使用原子整數和模函數。3個線程按順序打印備用值

下面的實現工作正常,第一個線程打印1,4,7而第二個打印2,5,8和第三個打印3,6,9,但問題是該序列不被維護,即輸出可以像1 ,3,2,4,5,7,8,6,9,而我希望序列被保持爲正確的線程,並且打印這些值。 一個條件是我不想使用同步。 [僅用於學習目的]

import java.util.concurrent.atomic.AtomicInteger; 

public class ThreeThreadsOrderedLockLess { 

    AtomicInteger sharedOutput = new AtomicInteger(0); 

    public static void main(String args[]) { 



     ThreeThreadsOrderedLockLess t = new ThreeThreadsOrderedLockLess(); 



     ThreadTasks t1 = t.new ThreadTasks(0); 
     ThreadTasks t2 = t.new ThreadTasks(1); 
     ThreadTasks t3 = t.new ThreadTasks(2); 

     Thread ts1 = new Thread(t1); 
     Thread ts2 = new Thread(t2); 
     Thread ts3 = new Thread(t3); 
     ts1.start(); 
     ts2.start(); 
     ts3.start(); 

    } 

    private class ThreadTasks implements Runnable { 

     private final int threadPosition; 


     public ThreadTasks(int threadPosition) { 
      super(); 

      this.threadPosition = threadPosition; 
     } 

     @Override 
     public void run() { 

      while (sharedOutput.get() < 9) { 

       if (sharedOutput.get() % 3 == this.threadPosition) { 

        System.out.println("Printing output for Thread: " 
          + this.threadPosition + " " 
          + sharedOutput.incrementAndGet()); 
       } 
      } 

     } 
    } 

} 
+1

如果不使用某種形式的同步,然後是cou rse這會發生! – 2013-03-10 13:39:57

+1

如果您希望序列行爲不使用線程。 – inf 2013-03-10 13:42:58

+0

@Eyal:正如我所說的那樣,保持正確的順序,即輸出shld是1,2,3,4,5,6,7,8,9。 – Lokesh 2013-03-10 13:47:47

回答

3

你應該先打印和增量後:

int value = sharedOutput.get() + 1; 
System.out.println("Printing output for Thread: " 
         + this.threadPosition + " " 
         + value); 
sharedOutput.incrementAndGet(); 

這就是說,所有的線程都很忙循環,這將導致100%的CPU使用率。您應該改爲同步這些線程。

+0

完美。適合我。 – Lokesh 2013-03-10 14:01:50

+0

如何在sysout中使用incrementAndGet()直接不同? – sgp15 2013-03-10 14:15:54

+0

在原始代碼中,調用'incrementAndGet()'。然後將返回的值與輸出消息的其餘部分連接起來。然後只打印消息。因此,在另一個線程看到AtomicInteger新值的消息的增量和打印之間有很長的時間。 – 2013-03-10 14:19:21

0

這是因爲每個線程的時間片由操作系統決定。因此,線程x可能會增加共享數字,但在打印之前,時間片傳遞給下一個線程y,該線程現在讀取共享數字並在遞增後打印它(假設線程y比線程x獲得更多時間以增加和打印共享號碼) 。

0

使用等待(),notify(),notifyall() Java的方法。
你也可以看看這些Tutorial這些方法。

希望這會有助於解決您的問題。 。 。

本例的輸出如下。

穿戴:1
GOT:1
穿戴:2
GOT:2
穿戴:3
GOT:3
穿戴:4
GOT:4
穿戴:5
GOT :5

+0

我已經說過我不想使用同步!所以沒有鎖意味着等待通知已經失去了圖像。 – Lokesh 2013-03-10 13:53:09

0

這應該工作:

package com.sid; 

import java.util.concurrent.atomic.AtomicInteger; 

public class NumberSequence { 

    private AtomicInteger sharedOutput = new AtomicInteger(0); 
    private Object object = new Object(); 

    public static void main(String args[]) { 

     NumberSequence t = new NumberSequence(); 

     ThreadTasks t1 = t.new ThreadTasks(0); 
     ThreadTasks t2 = t.new ThreadTasks(1); 
     ThreadTasks t3 = t.new ThreadTasks(2); 

     Thread ts1 = new Thread(t1); 
     Thread ts2 = new Thread(t2); 
     Thread ts3 = new Thread(t3); 

     ts1.start(); 
     ts2.start(); 
     ts3.start(); 

    } 

    private class ThreadTasks implements Runnable { 

     private final int threadPosition; 

     public ThreadTasks(int threadPosition) { 
      super(); 

      this.threadPosition = threadPosition; 
     } 

     @Override 
     public void run() { 

      while (sharedOutput.get() < 10) { 

       synchronized (object) { 

        if (sharedOutput.get() % 3 == this.threadPosition) { 

         if(sharedOutput.get() < 10) 
         System.out.println("Printing output for Thread: " 
           + this.threadPosition + " " 
           + sharedOutput.incrementAndGet()); 
        } 
       } 
      } 

     } 
    } 

} 
+1

您能否詳細說明您的答案,並添加關於您提供的解決方案的更多描述? – abarisone 2015-06-11 08:53:21

0

正確的同步將幫助您獲得明確的答案。我已經改進了實施,你應該解決你的問題。

int threadId; 
    int moduluos; 
    int numOfThreads; 

    public ThreadTasks(int id, int nubOfThreads) { 
     threadId = id; 
     this.numOfThreads = nubOfThreads; 
     moduluos = threadId%numOfThreads; 
    } 

    public void run() { 
     print(); 
    } 

    private void print() { 
     try { 
      while (true) { 
       synchronized (monitor) { 
        if (number.get() % numOfThreads != moduluos) { 
         monitor.wait(); 
        } else { 
         System.out.println("ThreadId [" + threadId 
           + "] printing -->" 
           + number.getAndIncrement()); 
         monitor.notifyAll(); 
        } 
       } 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 

} 
0
package test.mk.thread; 
import java.util.concurrent.atomic.AtomicInteger; 

public class MkThread2 { 
    int nextThreadToRun = 1; 
    int[] arr = {1,2,3,4,5,6,7,8,9,10,11}; 
    AtomicInteger nextArrayIndex = new AtomicInteger(0); 
    boolean token = true; 

    public static void main(String[] args) { 
     MkThread2 mkThread = new MkThread2(); 
     Thread t1 = new Thread(new Worker2(1, mkThread)); 
     Thread t2 = new Thread(new Worker2(2, mkThread)); 
     Thread t3 = new Thread(new Worker2(3, mkThread)); 
     t1.start(); 
     t2.start(); 
     t3.start(); 
    } 
} 


class Worker2 implements Runnable{ 
    volatile int threadNo; 
    private MkThread2 mkThread; 
    private String threadName; 

    Worker2(int threadNo, MkThread2 mkThread){ 
     this.threadNo = threadNo; 
     this.mkThread = mkThread; 
     this.threadName = "Thread:"+threadNo ; 
    } 

    public void run(){ 
     try{ 
      synchronized (mkThread) { 
       while(mkThread.token){ 
        while(threadNo != mkThread.nextThreadToRun){ 
         mkThread.wait(); 
        } 
        if(mkThread.token){//double checking 
         System.out.print(threadName+ "->" + mkThread.arr[mkThread.nextArrayIndex.get()]); 
         if(threadNo == 3) System.out.println(); 
         mkThread.nextThreadToRun = getNextThread(threadNo); 
         if(mkThread.nextArrayIndex.get() == mkThread.arr.length-1){ 
          mkThread.token = false; 
         } 
         mkThread.nextArrayIndex.incrementAndGet(); 
        } 
        mkThread.notifyAll(); 

       } 
      } 
     } 
     catch(Exception e){ 
      e.printStackTrace(); 
     } 
    } 

    private int getNextThread(int threadNo){ 
     int result = -1; 
     switch (threadNo) { 
     case (1): 
      result = 2; 
      break; 
     case (2): 
      result = 3; 
      break; 
     case (3): 
      result = 1; 
      break; 
     } 
     return result; 
    } 
} 
0
import java.util.concurrent.atomic.AtomicInteger; 
public class Print123456789 { 

public static void main(String[] args) { 
    print p1 = new print(0); 
    print p2 = new print(1); 
    print p3 = new print(2); 

    Thread t1 = new Thread(p1); 
    Thread t2 = new Thread(p2); 
    Thread t3 = new Thread(p3); 

    t1.start(); 
    t2.start();t3.start(); 


} 

} 



class print implements Runnable { 
private int threadNumber; 
private static AtomicInteger atomicInteger = new AtomicInteger(0); 
public print(int threadNumber) { 
    super(); 
    this.threadNumber = threadNumber; 
} 

public void run(){ 
    try{ 
    while(atomicInteger.get() < 10){ 
     synchronized (atomicInteger) { 

      if((atomicInteger.get()%3) == this.threadNumber){ 
       System.out.println(atomicInteger.getAndIncrement() + " Thread :" + this.threadNumber); 
       atomicInteger.notifyAll(); 
       } 
      else 
       atomicInteger.wait(); 
     } 
    } 
    }catch(InterruptedException e) 
    { 
     e.printStackTrace(); 
    } 
} 


} 
0

這可以使用阻塞隊列來更好地實現。定義一個持有阻塞隊列的工作者。工作人員在隊列中等待,直到收到一個號碼。它打印它接收的數字,增加它並將其傳遞給鏈中的下一個工作人員。完整的解決方案請參閱here

1

下面的代碼片段將按順序打印數字,所有線程將在任務完成後正常終止。 使用AtomicInteger,這是線程安全的打印數字和相同的邏輯可應用於打印任何數量的任何數量的線程。

 
    import java.util.concurrent.atomic.AtomicInteger; 

    public class PrintNumSequence 
    { 
     public static void main(String[] args) 
     { 
      AtomicInteger atomicInteger = new AtomicInteger(0); 
      new NumPrinter(atomicInteger, 0).start();// thread0 
      new NumPrinter(atomicInteger, 1).start();// thread1 
      new NumPrinter(atomicInteger, 2).start();// thread2 

     } 
    } 

    class NumPrinter extends Thread 
    { 

     private AtomicInteger atomicInteger; 
     private int    threadNum; 

     public NumPrinter(AtomicInteger atomicInteger, int threadNum) 
     { 
     this.atomicInteger = atomicInteger; 
     this.threadNum = threadNum; 
     } 

     @Override 
     public void run() 
     { 
     int num = atomicInteger.intValue(); 
     do 
     { 
      synchronized (atomicInteger) 
      { 
       num = atomicInteger.intValue(); 
       // If number is 9 then stop. 
       if (num > 9) 
       { 
        atomicInteger.notifyAll(); 
        break; 
       } 
       // 3 is number of threads 
       if ((num % 3) == threadNum) 
       { 
        System.out.println("Thread-" + threadNum + " -->" + num); 
        num = atomicInteger.incrementAndGet(); 

       } 
       atomicInteger.notifyAll(); 
       try 
       { 
        atomicInteger.wait(); 
       } 
       catch (InterruptedException e) 
       { 
        e.printStackTrace(); 
       } 
      } 
     } while (true); 
     } 
    } 
0
package threeThread; 

class Task implements Runnable { 

    String message; 
    ThreeThread lock; 
    int i = 0; 
    int p; 

    public Task(String text, ThreeThread obj, int p) { 
    message = text; 
    this.lock = obj; 
    this.p = p; 
    } 

    @Override 
    public void run() { 

    while(true) { 
     synchronized (lock) { 

      while(!((lock.status % 3) == 0) && p == 1){ 
       try { 
        lock.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 

      while(!((lock.status % 3) == 1) && p == 2){ 
       try { 
        lock.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 

      while(!((lock.status % 3) == 2) && p == 3){ 
       try { 
        lock.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      System.out.println("thread: " + p + " : " + message); 
      lock.status++; 
      lock.notifyAll(); 
     } 
    } 
    } 
} 

public class ThreeThread { 

    volatile int status = 0; 
    public static void main(String[] args) { 

    ThreeThread lock = new ThreeThread(); 
    Thread t1 = new Thread(new Task("Hello", lock,1)); 
    Thread t2 = new Thread(new Task("Good", lock,2)); 
    Thread t3 = new Thread(new Task("Morning", lock,3)); 
    t1.start(); 
    t2.start(); 
    t3.start(); 
    } 

} 
0

我把代碼打印1-100使用5個線程。可以使用任意數量的線程以循環方式打印輸出。

基本概念是鎖定一個對象並通知其他人執行值的打印。

public class PrintOneToHundredUsing5Threads { 

    public static void main(String[] args) { 
     List<Object> objList = new ArrayList<>(); 
     for (int i = 0; i < 5; i++) { 
      objList.add(new Object()); 
     } 
     for (int i = 0; i < 5; i++) { 
      Thread t = new Thread(new PrintThread(objList.get(i), objList.get((i + 1) % 5))); 
      t.setName("Thread" + i); 
      t.start(); 
     } 
    } 

} 

class PrintThread implements Runnable { 
    Object current; 
    Object next; 
    volatile static int i = 1; 

    PrintThread(Object cur, Object next) { 
     this.current = cur; 
     this.next = next; 
    } 

    @Override 
    public void run() { 
     for (; i <= 100;) { 
      synchronized (current) { 
       synchronized (next) { 
        next.notify(); 
        System.out.println(Thread.currentThread().getName() + " Value : " + i++); 
       } 
       try { 
        current.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 

      } 
     } 
    } 

} 
0

您可以使用下面的代碼使用多線程來打印序列號 -

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 

public class ThreadCall extends Thread { 

    private BlockingQueue<Integer> bq = new ArrayBlockingQueue<Integer>(10); 
    private ThreadCall next; 

    public void setNext(ThreadCall t) { 
     this.next = t; 
    } 

    public void addElBQ(int a) { 
     this.bq.add(a); 
    } 

    public ThreadCall(String name) { 
     this.setName(name); 
    } 

    @Override 
    public void run() { 
     int x = 0; 
     while(true) { 
      try { 
       x = 0; 
       x = bq.take(); 
       if (x!=0) { 
        System.out.println(Thread.currentThread().getName() + " =>" + x); 
        if (x >= 100) System.exit(0); // Need to stop all running threads 
        next.addElBQ(x+1); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     int THREAD_COUNT = 10; 
     List<ThreadCall> listThread = new ArrayList<>(); 

     for (int i=1; i<=THREAD_COUNT; i++) { 
      listThread.add(new ThreadCall("Thread " + i)); 
     } 

     for (int i = 0; i < listThread.size(); i++) { 
      if (i == listThread.size()-1) { 
       listThread.get(i).setNext(listThread.get(0)); 
      } 
      else listThread.get(i).setNext(listThread.get(i+1)); 
     } 

     listThread.get(0).addElBQ(1); 

     for (int i = 0; i < listThread.size(); i++) { 
      listThread.get(i).start(); 
     } 
    } 
} 

希望這將解決您的問題。

0

ThreadSynchronization類可用於在'n'no之間打印數字。順序的線程。 邏輯是在每個連續線程之間創建一個公共對象,並使用'wait','notify'按順序打印數字。 注意:最後一個線程將與第一個線程共享一個對象。

在運行程序之前,可以更改'maxThreads'值以增加或減少程序中的線程數。

import java.util.ArrayList; import java.util.List;

公共類ThreadSynchronization {

public static int i = 1; 
public static final int maxThreads = 10; 

public static void main(String[] args) { 
    List<Object> list = new ArrayList<>(); 
    for (int i = 0; i < maxThreads; i++) { 
     list.add(new Object()); 
    } 
    Object currObject = list.get(maxThreads - 1); 
    for (int i = 0; i < maxThreads; i++) { 
     Object nextObject = list.get(i); 
     RunnableClass1 a = new RunnableClass1(currObject, nextObject, i == 0 ? true : false); 
     Thread th = new Thread(a); 
     th.setName("Thread - " + (i + 1)); 
     th.start(); 
     currObject = list.get(i); 
    } 
} 

}

類RunnableClass實現Runnable {

private Object currObject; 
private Object nextObject; 
private boolean firstThread; 

public RunnableClass(Object currObject, Object nextObject, boolean first) { 
    this.currObject = currObject; 
    this.nextObject = nextObject; 
    this.firstThread = first; 
} 

@Override 
public void run() { 
    int i = 0; 
    try { 
     if (firstThread) { 
      Thread.sleep(5000); 
      firstThread = false; 
      System.out.println(Thread.currentThread().getName() + " - " + ThreadSynchronization.i++); 
      synchronized (nextObject) { 
       nextObject.notify(); 
      } 
     } 
     while (i++ < Integer.MAX_VALUE) { 
      synchronized (currObject) { 
       currObject.wait(); 
      } 
      System.out.println(Thread.currentThread().getName() + " - " + ThreadSynchronization.i++); 
      Thread.sleep(1000); 
      synchronized (nextObject) { 
       nextObject.notify(); 
      } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

}

0
public class PrintThreadsInSerial { 
    public static void main(String[] args) { 
    Thread t = new Thread(new Job()); 
    t.start(); 
    } 
} 

class Job implements Runnable { 
    @Override 
    public void run() { 
    while (true) { 
     for (int i = 1; i <= 3; i++) { 
     System.out.println(i); 
     } 
    } 
    } 
}