写两个线程,一个线程打印 1~52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z

通过这个例题学到了很多,记录下来便于以后常看,<线程通信>
/*
 * 写两个线程,一个线程打印1-52,另一个线程打印字母A-Z。打印 顺序为12A34B56C……5152Z>
 */
public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Object obj = new Object();
		Shuzi s = new Shuzi(obj);
		Zimu z = new Zimu(obj);
		Thread th1 = new Thread(s);
		Thread th2 = new Thread(z);
		th1.start();//数字的线程先运行,数字先执行
		th2.start();
		/*th2.start();
		 * th1.start();字母的线程先运行,则先执行字母
		 */
	}
}

class Shuzi implements Runnable{
	private Object obj;//声明一个类的引用
	public Shuzi(Object obj){
		this.obj = obj;	//通过构造器将共享的资源-->对象传进来
	}
	
	@Override
	public void run() {
		synchronized(obj){//给共享资源上锁
			for(int i = 1;i < 53;i++ ){
				System.out.println(i);
				if(i % 2 == 0){
					obj.notifyAll();//唤醒其他线程
				
					try {
						obj.wait();//等待并释放锁
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
		
	}
	
}

class Zimu implements Runnable{
	private Object obj;
	public Zimu(Object obj){
		this.obj = obj;	
	}
	
	@Override
	public void run() {
		synchronized(obj){
			for(int i = 0;i < 26;i++ ){
				System.out.println((char)(i+'A'));
					obj.notifyAll();//唤醒其他线程
				try {
					obj.wait();//释放锁等待
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
	}
	
}

这是线程间的通信的一个很有代表性的例子。过程如下:

1、创建两个线程实现Runnable接口重写run方法,一个用于打印数字,一个用于打印字母。

2、创建一个测试类,在测试类中创建一个Object类的对象(作为两个线程的共享资源,以便实现线程间的通信),通过各类的构造方法传递过去。

3、在两个类的run方法中都要用synchronized保证同步,即加锁。

4、在数字类中用for循环每打印两个数字就唤醒其他线程,释放锁,进入阻塞状态。

     在字母类中每打印一个字母就唤醒其他线程,释放锁,进入阻塞状态。

在写这个程序的时候有几点要注意的地方:

1、两个线程要使用同一个资源才需相互通信,所以在测试类中创建共享资源,并通过构造方法分别传到各线程类中。

2、两个线程哪个先运行(执行start())哪个就先获得资源并执行

3、在run方法体内写进程间的通信wait()和notifyall()时,一定要先写notifyall()再写wait()。

    原因:当你先写wait()时,本进程也进入休眠状态,再写notifyall()唤醒所有线程时本线程以及其他线程被一块唤醒,竞争同一个资源,就会造成死锁。

             所以一定要先唤醒其他线程,再让本线程阻塞!

你可能感兴趣的:(写两个线程,一个线程打印 1~52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z)