![](/img/trans.png)
[英]Using custom lock print number in sequence using two threads where one is printing even other is printing odd numbers
[英]Print Natural Sequence with help of 2 threads(1 is printing even and 2'nd is printing odd)
我已經厭倦了這個問題,最終我產生了一些疑問。 請幫幫我
懷疑:如果任何線程處於等待狀態,並且沒有其他線程通知該線程,那么它永遠不會結束嗎? 即使在使用等待(長毫秒)之后。
對於代碼:我的要求來自代碼(請參閱我的代碼):
a : 應該打印“Even Thread Finish”和“Odd Thread Finish”(訂單不是 imp ,但必須同時打印)
b: 同樣在主函數中應該打印“退出主線程”
實際發生的情況:經過多次運行,在某些情況下,它會打印“Even Thread Finish”,然后掛在這里,反之亦然。 在某些情況下,它會同時打印兩者。
它也從不打印“退出主線程”。
那么如何修改代碼,所以它必須打印所有 3 條語句。(當然“退出 Main..”最后,因為我使用 join 作為 main。)
簡而言之:主要開始-> t1 開始-> t2 開始,然后我需要t2/t1 完成-> 主要完成。
請幫我解決這個問題
這是我的代碼:
import javax.sql.CommonDataSource;
public class ThreadTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Share commonObj = new Share();
Thread even = new Thread(new EvenThread(commonObj));
Thread odd = new Thread(new OddThread(commonObj));
even.start();
odd.start();
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Exit Main Thread");
}
}
class EvenThread implements Runnable {
private Share commShare;
public EvenThread(Share obj) {
// TODO Auto-generated constructor stub
this.commShare = obj;
}
private int number = 2;
public void run() {
System.out.println("Even Thread start");
while (number <= 50) {
if (commShare.flag == true) {
System.out.println("Even Thread" + number);
number += 2;
commShare.flag = false;
synchronized(commShare) {
try {
commShare.notify();
commShare.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
commShare.notify();
}
} else {
synchronized(commShare) {
try {
commShare.notify();
commShare.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
commShare.notify();
}
}
}
System.out.println("Even Thread Finish");
}
}
class OddThread implements Runnable {
private int number = 1;
private Share commShare;
public OddThread(Share obj) {
// TODO Auto-generated constructor stub
this.commShare = obj;
}
public void run() {
System.out.println("Odd Thread start");
while (number <= 50) {
if (commShare.flag == false) {
System.out.println("Odd Thread :" + number);
number += 2;
commShare.flag = true;
synchronized(commShare) {
try {
commShare.notify();
commShare.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
commShare.notify();
}
}
}
System.out.println("Odd Thread Finish");
}
}
class Share {
Share sharedObj;
public boolean flag = false;
}
雖然這不是您問題的確切答案,但此實現是您問題的替代方案。
public class EvenOddThreads {
public static void main(String[] args) {
Thread odd = new Thread(new OddThread(), "oddThread");
Thread even = new Thread(new EvenThread(), "Even Thread");
odd.start();
even.start();
try {
odd.join();
even.join();
System.out.println("Main thread exited");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class OddThread implements Runnable{
public void run() {
synchronized (CommonUtil.mLock) {
System.out.println(Thread.currentThread().getName()+"---> job starting");
int i = 1;
while(i<50){
System.out.print(i + "\t");
i = i + 2;
CommonUtil.mLock.notify();
try {
CommonUtil.mLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("OddThread---> job completed");
CommonUtil.mLock.notify();
}
}
}
class EvenThread implements Runnable{
@Override
public void run() {
synchronized (CommonUtil.mLock) {
System.out.println(Thread.currentThread().getName()+"---> job started");
int i =2;
while(i<50){
System.out.print(i + "\t");
i = i+2;
CommonUtil.mLock.notify();
try {
CommonUtil.mLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("EvenThread---> job completed");
CommonUtil.mLock.notify();
}
}
}
class CommonUtil{
static final Object mLock= new Object();
}
輸出:
oddThread---> job starting
1 Even Thread---> job started
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 EvenThread---> job completed
OddThread---> job completed
Main thread exited
好吧,我花了三個小時閱讀Java 同步教程(非常好的教程),然后閱讀了有關wait、notify 和 notifyAll的更多信息,最后我得到了使用 N 個線程從 A 到 B 計數的程序,將 N 設置為2 你有奇數和偶數。
此外,我的程序沒有任何注釋,因此在嘗試理解此代碼之前,請務必閱讀教程。
這可能是關於線程和鎖監視器的練習,但沒有任何並行可以給您帶來好處。
在您的代碼中,當線程 1(OddThread 或 EvenThread)結束其工作並打印出“Odd Thread Finish”(或“Even Thread Finish”)時,另一個線程 2 正在等待一個永遠不會發生的 notify() 或 notifyAll()因為第一次結束了。
您必須更改 EvenThread 和 OddThread,在 while 循環之后添加一個同步塊,並在 commShare 上調用通知。 我刪除了第二個 if 分支,因為通過這種方式,您不會繼續檢查 while 條件,但很快就會等待 commShare。
class EvenThread implements Runnable {
private Share commShare;
private int number = 2;
public EvenThread(Share obj) {
this.commShare = obj;
}
public void run() {
System.out.println("Even Thread start");
while (number <= 50) {
synchronized (commShare) {
if (commShare.flag) {
System.out.println("Even Thread:" + number);
number += 2;
commShare.flag = false;
}
commShare.notify();
try {
commShare.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
synchronized (commShare) {
commShare.notify();
System.out.println("Even Thread Finish");
}
}
}
class OddThread implements Runnable {
private int number = 1;
private Share commShare;
public OddThread(Share obj) {
this.commShare = obj;
}
public void run() {
System.out.println("Odd Thread start");
while (number <= 50) {
synchronized (commShare) {
if (!commShare.flag) {
System.out.println("Odd Thread: " + number);
number += 2;
commShare.flag = true;
}
commShare.notify();
try {
commShare.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
synchronized (commShare) {
commShare.notify();
System.out.println("Odd Thread Finish");
}
}
最后,總的來說,您必須為您啟動的每個線程加入。 確定 Thread.currentThread() 只返回您的線程之一嗎? 我們已經啟動了兩個線程,我們應該加入這些線程。
try {
even.join();
odd.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
它也從不打印“退出主線程”。
那是因為可能是因為您的線程正在等待某人notify()
的鎖,但由於錯過了信號或沒有人向他們發出信號,他們永遠不會退出等待狀態。 為此,最好的解決方案是使用:
public final void wait(long timeout)
throws InterruptedException
導致當前線程等待,直到另一個線程為此對象調用
notify()
方法或notifyAll()
方法,或者指定的時間量已經過去。
此重載方法將等待其他線程通知特定時間,然后在超時發生時返回。 因此,在丟失信號的情況下,線程仍將恢復其工作。
注意:從等待狀態返回后,始終再次檢查PRE-CONDITION ,因為它可能是Spurious Wakeup 。
這是我一段時間以前編寫的程序風格。
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
private static int range = 10;
private static volatile AtomicInteger present = new AtomicInteger(0);
private static Object lock = new Object();
public static void main(String[] args) {
new Thread(new OddRunnable()).start();
new Thread(new EvenRunnable()).start();
}
static class OddRunnable implements Runnable{
@Override
public void run() {
while(present.get() <= range){
if((present.get() % 2) != 0){
System.out.println(present.get());
present.incrementAndGet();
synchronized (lock) {
lock.notifyAll();
}
}else{
synchronized (lock) {
try {
lock.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
}
}
static class EvenRunnable implements Runnable{
@Override
public void run() {
while(present.get() <= range){
if((present.get() % 2) == 0){
System.out.println(present.get());
present.incrementAndGet();
synchronized (lock) {
lock.notifyAll();
}
}else{
synchronized (lock) {
try {
lock.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
}
}
}
查看解決方案,我保留了一個lock
,用於通知偶數或奇數線程的機會。 如果偶數線程發現當前的數字不是偶數,它就等待lock
並希望奇數線程在打印該奇數時通知它。 同樣,它也適用於奇數線程。
我並不是說這是最好的解決方案,但這是第一次嘗試的結果,其他一些選擇也是可能的。
另外我想指出,這個問題雖然作為一種實踐是好的,但請記住,你沒有在那里做任何平行的事情。
我不會投票支持使用wait()
和notify().
您可以通過更復雜的工具(如semaphore
、 countDownLatch
、 CyclicBarrier
完成wait
和notify
操作。 您可以在著名書籍 Effective java 的第 69 項中找到此建議, 更喜歡並發實用程序等待和通知。
即使在這種情況下我們根本不需要這些東西,我們可以通過一個簡單的volatile
boolean
變量來實現這個功能。 對於停止線程,最好的方法是使用interrupt
。 在一定的時間或一些預定義的條件之后,我們可以中斷線程。 請附上我的實現:
用於打印偶數的線程 1:
public class MyRunnable1 implements Runnable
{
public static volatile boolean isRun = false;
private int k = 0 ;
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
if(isRun){
System.out.println(k);
k+=2;
isRun=false;
MyRunnable2.isRun=true;
}
}
}
}
用於打印偶數的線程 2:
public class MyRunnable2 implements Runnable{
public static volatile boolean isRun = false;
private int k = 1 ;
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
if(isRun){
System.out.println(k);
k+=2;
isRun=false;
MyRunnable1.isRun=true;
}
}
}
}
現在驅動上述線程的主要方法
public class MyMain{
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(new MyRunnable1());
Thread t2 = new Thread(new MyRunnable2());
MyRunnable1.isRun=true;
t1.start();
t2.start();
Thread.currentThread().sleep(1000);
t1.interrupt();
t2.interrupt();
}
}
可能有些地方你需要稍微改變一下,這只是一個骨架實現。 希望它有所幫助,如果您需要其他東西,請告訴我。
public class PrintNumbers {
public static class Condition {
private boolean start = false;
public boolean getStart() {
return start;
}
public void setStart(boolean start) {
this.start = start;
}
}
public static void main(String[] args) {
final Object lock = new Object();
// condition used to start the odd number thread first
final Condition condition = new Condition();
Thread oddThread = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
for (int i = 1; i <= 10; i = i + 2) { //For simplicity assume only printing till 10;
System.out.println(i);
//update condition value to signify that odd number thread has printed first
if (condition.getStart() == false) {
condition.setStart(true);
}
lock.notify();
try {
if (i + 2 <= 10) {
lock.wait(); //if more numbers to print, wait;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
Thread evenThread = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
for (int i = 2; i <= 10; i = i + 2) { //For simplicity assume only printing till 10;
// if thread with odd number has not printed first, then wait
while (condition.getStart() == false) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i);
lock.notify();
try {
if (i + 2 <= 10) { //if more numbers to print, wait;
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
oddThread.start();
evenThread.start();
}
}
我使用 25 個線程的 ReentrantLock 做到了。 一個線程打印一個數字,它會通知其他。
public class ReentrantLockHolder
{
private Lock lock;
private Condition condition;
public ReentrantLockHolder(Lock lock )
{
this.lock=lock;
this.condition=this.lock.newCondition();
}
public Lock getLock() {
return lock;
}
public void setLock(Lock lock) {
this.lock = lock;
}
public Condition getCondition() {
return condition;
}
public void setCondition(Condition condition) {
this.condition = condition;
}
}
public class PrintThreadUsingReentrantLock implements Runnable
{
private ReentrantLockHolder currHolder;
private ReentrantLockHolder nextHolder;
private PrintWriter writer;
private static int i=0;
public PrintThreadUsingReentrantLock(ReentrantLockHolder currHolder, ReentrantLockHolder nextHolder ,PrintWriter writer)
{
this.currHolder=currHolder;
this.nextHolder=nextHolder;
this.writer=writer;
}
@Override
public void run()
{
while (true)
{
writer.println(Thread.currentThread().getName()+ " "+ ++i);
try{
nextHolder.getLock().lock();
nextHolder.getCondition().signal();
}finally{
nextHolder.getLock().unlock();
}
try {
currHolder.getLock().lock();
currHolder.getCondition().await();
}catch (InterruptedException e)
{
e.printStackTrace();
}
finally{
currHolder.getLock().unlock();
}
}
}
}
public static void main(String[] args)
{
PrintWriter printWriter =null;
try {
printWriter=new PrintWriter(new FileOutputStream(new File("D://myFile.txt")));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ReentrantLockHolder obj[]=new ReentrantLockHolder[25];
for(int i=0;i<25;i++)
{
obj[i]=new ReentrantLockHolder(new ReentrantLock());
}
for(int i=0;i<25;i++)
{
Thread t1=new Thread(new PrintThreadUsingReentrantLock(obj[i], obj[i+1 == 25 ? 0 : i+1],printWriter ),"T"+i );
t1.start();
}
}
我嘗試了類似的東西,其中線程 1 打印奇數,線程 2 以正確的順序打印偶數,並且當打印結束時,將打印您建議的所需消息。 請看一下這段代碼
package practice;
class Test {
private static boolean oddFlag = true;
int count = 1;
private void oddPrinter() {
synchronized (this) {
while(true) {
try {
if(count < 10) {
if(oddFlag) {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + ": " + count++);
oddFlag = !oddFlag;
notifyAll();
}
else {
wait();
}
}
else {
System.out.println("Odd Thread finished");
notify();
break;
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private void evenPrinter() {
synchronized (this) {
while (true) {
try {
if(count < 10) {
if(!oddFlag) {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + ": " + count++);
oddFlag = !oddFlag;
notify();
}
else {
wait();
}
}
else {
System.out.println("Even Thread finished");
notify();
break;
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException{
final Test test = new Test();
Thread t1 = new Thread(new Runnable() {
public void run() {
test.oddPrinter();
}
}, "Thread 1");
Thread t2 = new Thread(new Runnable() {
public void run() {
test.evenPrinter();
}
}, "Thread 2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Main thread finished");
}
}
package test;
public class Interview2 {
public static void main(String[] args) {
Obj obj = new Obj();
Runnable evenThread = ()-> {
synchronized (obj) {
for(int i=2;i<=50;i+=2) {
while(!obj.printEven) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i);
obj.printEven = false;
obj.notify();
}
}
};
Runnable oddThread = ()-> {
synchronized (obj) {
for(int i=1;i<=49;i+=2) {
while(obj.printEven) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i);
obj.printEven = true;
obj.notify();
}
}
};
new Thread(evenThread).start();
new Thread(oddThread).start();
}
}
class Obj {
boolean printEven;
}
這是非常通用的解決方案。 它使用信號量在線程之間進行信號傳遞。 這是 N 個線程依次依次打印 M 個自然數的通用解決方案。 也就是說,如果我們有 3 個線程並且我們想要打印 7 個自然數,輸出將是:
主題 1 : 1
主題 2 : 2
主題 3 : 3
主題 1 : 4
主題 2 : 5
主題 3 : 6
主題 1 : 7
import java.util.concurrent.Semaphore;
/*
* Logic is based on simple idea
* each thread should wait for previous thread and then notify next thread in circular fashion
* There is no locking required
* Semaphores will do the signaling work among threads.
*/
public class NThreadsMNaturalNumbers {
private static volatile int nextNumberToPrint = 1;
private static int MaxNumberToPrint;
public static void main(String[] args) {
int numberOfThreads = 2;
MaxNumberToPrint = 50;
Semaphore s[] = new Semaphore[numberOfThreads];
// initialize Semaphores
for (int i = 0; i < numberOfThreads; i++) {
s[i] = new Semaphore(0);
}
// Create threads and initialize which thread they wait for and notify to
for (int i = 1; i <= numberOfThreads; i++) {
new Thread(new NumberPrinter("Thread " + i, s[i - 1], s[i % numberOfThreads])).start();
}
s[0].release();// So that First Thread can start Processing
}
private static class NumberPrinter implements Runnable {
private final Semaphore waitFor;
private final Semaphore notifyTo;
private final String name;
public NumberPrinter(String name, Semaphore waitFor, Semaphore notifyTo) {
this.waitFor = waitFor;
this.notifyTo = notifyTo;
this.name = name;
}
@Override
public void run() {
while (NThreadsMNaturalNumbers.nextNumberToPrint <= NThreadsMNaturalNumbers.MaxNumberToPrint) {
waitFor.acquireUninterruptibly();
if (NThreadsMNaturalNumbers.nextNumberToPrint <= NThreadsMNaturalNumbers.MaxNumberToPrint) {
System.out.println(name + " : " + NThreadsMNaturalNumbers.nextNumberToPrint++);
notifyTo.release();
}
}
notifyTo.release();
}
}
}
這個類打印偶數:
public class EvenThreadDetails extends Thread{
int countNumber;
public EvenThreadDetails(int countNumber) {
this.countNumber=countNumber;
}
@Override
public void run()
{
for (int i = 0; i < countNumber; i++) {
if(i%2==0)
{
System.out.println("Even Number :"+i);
}
try {
Thread.sleep(2);
} catch (InterruptedException ex) {
// code to resume or terminate...
}
}
}
}
這個類打印奇數:
public class OddThreadDetails extends Thread {
int countNumber;
public OddThreadDetails(int countNumber) {
this.countNumber=countNumber;
}
@Override
public void run()
{
for (int i = 0; i < countNumber; i++) {
if(i%2!=0)
{
System.out.println("Odd Number :"+i);
}
try {
Thread.sleep(2);
} catch (InterruptedException ex) {
// code to resume or terminate...
}
}
}
}
這是主類:
public class EvenOddDemo {
public static void main(String[] args) throws InterruptedException
{
Thread eventhread= new EvenThreadDetails(100);
Thread oddhread=new OddThreadDetails(100);
eventhread.start();
oddhread.start();
}
}
I have done it this way and its working...
class Printoddeven{
public synchronized void print(String msg){
try {
if(msg.equals("Even"))
{
for(int i=0;i<=10;i+=2){
System.out.println(msg+" "+i);
Thread.sleep(2000);
notify();
wait();
}
}
else{
for(int i=1;i<=10;i+=2){
System.out.println(msg+" "+i);
Thread.sleep(2000);
notify();
wait();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class PrintOdd extends Thread{
Printoddeven oddeven;
public PrintOdd(Printoddeven oddeven){
this.oddeven=oddeven;
}
public void run(){
oddeven.print("ODD");
}
}
class PrintEven extends Thread{
Printoddeven oddeven;
public PrintEven(Printoddeven oddeven){
this.oddeven=oddeven;
}
public void run(){
oddeven.print("Even");
}
}
public class mainclass
{
public static void main(String[] args)
{
Printoddeven obj = new Printoddeven();//only one object
PrintEven t1=new PrintEven(obj);
PrintOdd t2=new PrintOdd(obj);
t1.start();
t2.start();
}
}
public class Driver {
static Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int itr = 1; itr < 51; itr = itr + 2) {
synchronized (lock) {
System.out.print(" " + itr);
try {
lock.notify();
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("\nEven Thread Finish ");
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
for (int itr = 2; itr < 51; itr = itr + 2) {
synchronized (lock) {
System.out.print(" " + itr);
try {
lock.notify();
if(itr==50)
break;
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("\nOdd Thread Finish ");
}
});
try {
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Exit Main Thread");
} catch (Exception e) {
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.