Java多线程与并发应用-(4)-传统线程通信技术试题

package com.lipeng;

public class LoopDemo {

	/**
	 * 线程A循环10次,然后线程B循环100次,然后A再循环10次,然后B再循环100次。如此循环50次。
	 * lipeng
	 * 2015-4-10
	 * @param args
	 */
	public static void main(String[] args) {
		MyTask task=new MyTask();
		RunA runA=new RunA(task);
		RunB runB=new RunB(task);
		new Thread(runA,"A").start();  //每个线程的start方法只能运行一次,但Run方法在不同的线程中可以运行多次。
		new Thread(runB,"B").start();
	}
}

class RunA implements Runnable
{
	private MyTask task;
	public RunA(MyTask task)
	{
		this.task=task;
	}
	@Override
	public void run() {
		try {
			for(int i=0;i<50;i++)
			{
				task.A();
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class RunB implements Runnable
{
	private MyTask task;
	public  RunB(MyTask task)
	{
		this.task=task;
	}
	@Override
	public void run() {
		try {
			for(int i=0;i<50;i++)
			{
				task.B();
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class MyTask
{
	private boolean aGo=true;//切换开关,当true时A执行,false时B执行,执行完后切换条件
	public synchronized void A()throws Exception{
		while(!aGo)  //为何不用if???
		{
			//A 不能运行,等待
			this.wait();
		}
		for(int i=0;i<10;i++)
		{
			System.out.println("AAAAA--------------"+i);
		}
		//运行完之后,将aGo切换为FALSE,让B运行
		aGo=false;
		this.notify();//唤醒一个正在等待的线程
	}

	public synchronized void B()throws Exception{
		while(aGo)
		{
			//B 不能运行,等待
			this.wait();
		}
		for(int i=0;i<100;i++)
		{
			System.out.println("B--------------"+i);
		}
		//运行完之后,将aGo切换为true,让A运行
		aGo=true;
		this.notify();//唤醒一个正在等待的线程
	}
}

说明:

1. 如果有大于两个多线程在执行,最好用notifyAll,为什么?

例如,如果本例中多起几个线程,如果此时有A1,B1线程在wait,某个A线程执行完,将aGo置为false,并唤醒正在等待锁的其中一个线程,A1或B1,如果此时正好A1线程抢到了CPU,则A1运行,判断方法A1进入wait状态,而B1由于没有被唤醒,之后继续等待,那么到最后,A1和B1都处于wait状态,造成了死锁。

而如果改为notifyAll的话,A1和B1都被唤醒,抢到锁的线程先执行,如果A1抢到的话,继续等待,然后B1继续执行,因为此时aGo=false,所以B1执行,将aGo=true,A1继续执行完毕。

结论:只要A和B启动的线程的个数不同,就可能造成死锁的情况。

2.
判断aGo的地方为什么要使用while,if不行吗?在wait方法说明中,也推荐使用while,因为在某些特定的情况下,线程有可能被假唤醒,使用while会循环检测更稳妥。在本例中,A和B应该是交替运行的,但是如果多启动几个线程,如果有A1线程在等待(wait)状态,而A2线程执行完毕,aGo设置为false,唤醒正在等待的线程(可能是A也可能是B),如果是A被唤醒的话,如果用了if而不是while,那么A执行,这样A就连续执行了两遍,不符合我们的设计要求,但如果换用while的话,即使A被唤醒,他会再次判断aGo的值,发现是false,则继续等待。直到B线程将其唤醒。

时间: 04-13

Java多线程与并发应用-(4)-传统线程通信技术试题的相关文章

Java多线程与并发——死锁与中断线程

过多的同步有可能出现死锁,死锁的操作一般是在程序运行的时候才有可能出现. 多线程中要进行资源的共享,就需要同步,但同步过多,就可能造成死锁. 死锁例子: package com.vince; /** * 线程死锁 * @author acer * */ public class DeadThreadDemo { public static void main(String[] args) { new DeadThread(); } } //顾客 class Customer{ public sy

Java多线程与并发库高级应用之线程数据交换Exchanger

JDK1.5提供了Exchanger用于两个线程的数据交换.两个线程先后到达交换点,先到达的线程会等待后到达的线程,然后两个线程互相交换数据,交换后双方持对方的数据. Exchanger只提供了一个构造器: Exchanger():创建一个新的Exchanger. Exchanger中也只有两个方法: V exchange(V x): 等待另一个线程到达此交换点(除非当前线程被中断),然后将给定的对象传送给该线程,并接收该线程的对象. V exchange(V x, long timeout,

Java多线程与并发---学习总结(很详细)

Java多线程与并发---学习总结(很详细) 1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓存一致性:多处理器系统中,因为共享同一主内存,当多个处理器的运算任务都设计到同一块内存区域时,将可能导致各自的缓存数据不一致的情况,则同步回主内存时需要遵循一些协议. 乱序执行优化:为了使得处理器内部的运算单位能尽量被充分利用. 2.      JAVA

JAVA多线程和并发基础面试问答(转载)

原文链接:http://www.cnblogs.com/dolphin0520/p/3932934.html 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题. Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环境是一个包含

JAVA多线程和并发基础面试问答

原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题.(校对注:非常赞同这个观点) Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环

JAVA多线程和并发基础面试问答【转】

JAVA多线程和并发基础面试问答 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题.(校对注:非常赞同这个观点) Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环境是一个包含了不同的类和程序的单 一进程.线程可以被称为轻量

JAVA 多线程和并发学习笔记(三)

Java并发编程中使用Executors类创建和管理线程的用法 1.类 Executors Executors类可以看做一个“工具类”.援引JDK1.6 API中的介绍: 此包中所定义的 Executor.ExecutorService.ScheduledExecutorService.ThreadFactory 和 Callable 类的工厂和实用方法.此类支持以下各种方法: 创建并返回设置有常用配置字符串的 ExecutorService 的方法. 创建并返回设置有常用配置字符串的 Sche

Java多线程与并发应用-(5)-如何优雅的使用ThreadLocal类

内容来自,张孝祥老师的张孝祥-Java多线程与并发库高级应用>视频教程 package com.lipeng; public class MyThreadLocalTest2 { private final static MyThreadLocal<String> myThreadLocal=new MyThreadLocal<String>(); /** * @param args */ public static void main(String[] args) { ne

17、JAVA多线程和并发基础面试问答

JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题.(校对注:非常赞同这个观点) Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(se