多线程问题,新手求解答。

czhang1991 2016-09-07 05:01:03
一道面试题:子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次。将主线程或者子线程循环次数增加的时候输出结果出错,代码如下:

public class Test{
private static boolean mainThread=false;
public static void main(String[] args){
new Thread(new Runnable(){
public void run() {
for(int i=0 ; i<50; i++){
synchronized (Test.class) {
if(mainThread){
try {
Test.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=0; j<10; j++){
System.out.println(Thread.currentThread().getName()+", i="+i+", j="+j);
}
mainThread=true;
Test.class.notify();
}
}
}

}).start();
for(int i =0; i<50; i++){
synchronized (Test.class) {
if(!mainThread){
try {
Test.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=0; j<3000; j++){
System.out.println(Thread.currentThread().getName()+", i="+i+", j="+j);
}
mainThread=false;
Test.class.notify();
}
}
}
}

结果如下,循环直接从48开始了:
main, i=48, j=1846
main, i=48, j=1847
main, i=48, j=1848
main, i=48, j=1849
main, i=48, j=1850
main, i=48, j=1851
main, i=48, j=1852
main, i=48, j=1853
main, i=48, j=1854
main, i=48, j=1855
main, i=48, j=1856
main, i=48, j=1857
.......
...全文
173 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
rickylin86 2016-09-07
  • 打赏
  • 举报
回复
类似这种多线程交替执行目的可以使用某个变量来指出对应对应线程.如上面的代码.但是这种方式存在一定死锁的可能性. 比如你上面的题目,如果main线程执行过程中出现异常.那么这个时候子线程将会出现死锁的现象. 另一种可以考虑的处理方式是采用公平锁.代码如下.

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;


public class Test{
	public static void main(String[] args){
		String main = Thread.currentThread().getName();
		ReentrantLock lock = new ReentrantLock(true);
		Thread thread = new Thread(new Task("Task",lock));
		thread.start();
		
		//为了子线程先执行,main线程需要睡眠.
		try{
			TimeUnit.NANOSECONDS.sleep(1);
		}catch(InterruptedException e){
			e.printStackTrace();
		}

		for(int i = 0 ; i < 50 ; i ++){
			try{
				lock.lock();
				System.out.printf("%s:%d\n",main,i);
				/*
				for(int j = 0 ; j < 100 ; j ++){
					System.out.printf("%s:%d:%d\n",main,i,j);
				}*/
			}finally{
				lock.unlock();
			}
			
		}
	}
}

class Task implements Runnable{
	public Task(String name,ReentrantLock lock){
		this.name = name;
		this.lock = lock;
	}


	@Override
	public void run(){
			for(int i = 0 ; i < 50 ; i ++){
				try{
					lock.lock();
					System.out.printf("%s:%d\n",name,i);
					/*
					for(int j = 0 ; j < 10 ; j ++){
						System.out.printf("%s:%d:%d\n",name,i,j);
					}
					*/
				}finally{
					lock.unlock();
				}
				
			}
		
	}

	private String name;
	private ReentrantLock lock;
}

rickylin86 2016-09-07
  • 打赏
  • 举报
回复

public class Test{
	static boolean flag = false;
	public static void main(String[] args){
		Thread thread = new Thread(new Task("Task"));
		thread.start();
		String main = Thread.currentThread().getName();
		for(int i = 0 ; i < 50 ; i ++){
			try{
				synchronized(Test.class){
					while(!flag){
						Test.class.wait();
					}
					System.out.printf("%s:%d\n",main,i);
					/*
					for(int j = 0 ; j < 100 ; j ++){
						System.out.printf("%s:%d:%d\n",main,i,j);
					}*/
					flag = false;
					Test.class.notifyAll();
				}
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
	}
}

class Task implements Runnable{
	
	public Task(String name){
		this.name = name;
	}

	@Override
	public void run(){
		for(int i = 0 ; i < 50 ; i ++){
			try{
				synchronized(Test.class){
					while(Test.flag){
						Test.class.wait();
					}
					System.out.printf("%s:%d\n",name,i);
					/*
					for(int j = 0 ; j < 10 ; j ++){
						System.out.printf("%s:%d:%d\n",name,i,j);
					}*/
					Test.flag = true;
					Test.class.notifyAll();
				}
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
	}

	private String name;
}
onepiecer1 2016-09-07
  • 打赏
  • 举报
回复
不是直接从48开始,是前面的在console里面没有显示出来,被后面的顶掉了
soton_dolphin 2016-09-07
  • 打赏
  • 举报
回复

public class Indicator{
	// switcher = 0: main is running; switcher = 1: sub is running
	private short switcher;
	
	
	public void executeMain(){
			switcher = 0;
	}
	
	public void executeSub(){
			switcher = 1;
	}
	
	public short getSwitcher(){
		return switcher;
	}
}

public class SubThread implements Runnable{
	
	private Indicator indicator;
	
	public SubThread(Indicator ind){
		this.indicator = ind;
	}
	
	public void run(){
		int counter = 0;
		synchronized(indicator){
			try{
				for(int i = 0; i < 50; i++){
					if(indicator.getSwitcher() == 0){
						indicator.wait();
					}
					
					for(int j = 0; j < 10; j ++){
						System.out.println(Thread.currentThread().getName() + " j = " + j);
					}
					
					System.out.println(Thread.currentThread().getName() + " after " + (++counter) + " loops of 50" );
					indicator.executeMain();
					indicator.notify();
				}
			}catch(InterruptedException ie){
				ie.printStackTrace();
			}
		}
	}

}


public class ThreadSwitching{

	
	public static void main(String[] args){
		
		Indicator ind = new Indicator();
		SubThread st = new SubThread(ind);
		
		Thread subThread = new Thread(st);
		subThread.start();
		int counter = 0;
		synchronized(ind){
			try{
				for(int i = 0; i < 50; i++){
					if(ind.getSwitcher() == 1){
						ind.wait();
					}
					
					for(int j = 0; j < 100; j ++){
						System.out.println(Thread.currentThread().getName() + " j = " + j);
					}
					
					System.out.println(Thread.currentThread().getName() + " after " + (++counter) + " loops of 50" );
					ind.executeSub();
					ind.notify();
				}
			}catch(InterruptedException ie){
				ie.printStackTrace();
			}
		}
	}

}

soton_dolphin 2016-09-07
  • 打赏
  • 举报
回复
用 Thread.join() 写
czhang1991 2016-09-07
  • 打赏
  • 举报
回复
找到原因了,eclipse 里console缓存区大小的问题,缓存区不够大导致只显示后面的内容。 在windows->preference->run/debug->console里设置limit console output 为false就好了。 谢谢各位的回答。
逸花城 2016-09-07
  • 打赏
  • 举报
回复
没必要这么复杂,强制让另一个线程运行就行了。

62,626

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧