多线程实现继承Thread和实现Runnable接口的用两个线程打印1-100,且线程1,线程2交替打印

方式一:使用继承Thread类的方式:

package com.atguigu.java.Test;

public class ReplacePrint extends Thread {
     

//	因为此处使用的是继承Thread类,在测试类中要创建多个子类对象
//	将循环遍历参数i设置为static的,这就要每个子类对象循环条件中的i值共用同一个数据
	static int i = 0;

	@Override
	public void run() {
     
		
//		 初始化i值为从1到100
		for (i = 1; i <= 100;) {
     
/**
 * 		使用“类.class”充当监视器,这里的ThreadRunnable.class是我自己在同目录下创建的
 * 一个类,大家随意,可以使用任意一个类充当监视器,
 * 注意:不允许将该监视器放在for循环上面,原因如下
 * 因为在线程一在最初进入的同步监视器的时候,是禁止别的线程进入的,此时线程二在
 * synchornized外部等待线程一调用wait()释放监视器。
 * 1)、如果将synchronized(同步监视器)放在for循环外面
 * 最开始的时,线程一进入同步监视器,执行for循环的i=1赋值操作,此时线程一的i=1,
 * 因为是i是static的,线程一修改了i的值,所以在外部等待的线程二的i也是1,等到线程1执
 * 行完内部输出代码以后,对i进行i++操作,此时又将线程一、二i的值修改成2,接下来线程一
 * 调用wait()方法释放当前监视器,线程一一旦释放监视器,线程二就进来了,线程二首次操作
 * for循环,就先执行for循环中的,i=1赋值操作,所以,这次执行的for循环又将线程一、二的
 * i值置为1了,所以打印出来就会出现
 * 线程一:1
 * 线程二:1
 * 线程一:2
 * 线程二:3
 * 线程一:4
 * 线程二:5
 * ...........
 * 线程二:97
 * 线程一:98
 * 线程二:99
 * 线程一:100
 * 线程一、二首次打印出来的都是一样的
 * 
 * 2)、如果将synchronized(同步监视器)放在for循环下面
 * 初次在线程二堵塞在synchronized(同步监视器)的时候,其实线程二已将执行完毕for循环中的i=1赋值操作,
 * 后续的循环将不再执行该操作,这就是为不能将synchronized(同步监视器)放在for循环上面的原因
 * 
 */
			synchronized (ThreadRunnable.class) {
     
//				此处必须使用“监视器.notify()”唤醒被阻塞的线程
				ThreadRunnable.class.notify();
//				输出线程名+i值
				System.out.println(Thread.currentThread().getName() + ":" + i);
				/**
				 * 在使线程阻塞的之前先修改i的值,线程的阻塞会释放当前的同步监视器, 
				 * 一旦T1线程阻塞,后面的线程T2就可以进入同步监视器内部,此时的i
				 * 值还是T1线程使用的值,所以此时要将静态属性值修改+1,再释放同步监视器
				 */
				try {
     
					i++;
					ThreadRunnable.class.wait();
				} catch (InterruptedException e) {
     
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

测试代码

		ReplacePrint replacePrint=new ReplacePrint();
		ReplacePrint replacePrint1=new ReplacePrint();
		replacePrint.start();
		replacePrint.setName("线程一");
		replacePrint1.start();
		replacePrint1.setName("线程二");

运行结果:
多线程实现继承Thread和实现Runnable接口的用两个线程打印1-100,且线程1,线程2交替打印_第1张图片

方式二:使用实现Runnable接口的类

package com.atguigu.java.Test;

public class ReplacePrintRunnable implements Runnable {
     
int i=1;
	@Override
	public void run() {
     
			
				while (i<=100) {
     
//					此处的synchronized(监视器)放在while前面和后面都没影响
					synchronized (this) {
     
				this.notify();
				System.out.println(Thread.currentThread().getName() + ":" + i);
				try {
     
					 i++;
					this.wait();
				} catch (InterruptedException e) {
     
					e.printStackTrace();
				}
			}
		}
	}
}

实现了Runnnable接口的类使用了while判断,当然也可以类比实现方式一使用for循环,但是要注意synchronized放置位置

测试代码:

		 ReplacePrintRunnable rpn=new ReplacePrintRunnable();
		 Thread thread=new Thread(rpn);
		 Thread thread1=new Thread(rpn);
		 thread.start();
		 thread.setName("线程一");
		 thread1.start();
		thread1.setName("线程二");

结果:
多线程实现继承Thread和实现Runnable接口的用两个线程打印1-100,且线程1,线程2交替打印_第2张图片

你可能感兴趣的:(java,多线程)