方式一:使用继承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循环下面
* 初次在线程二堵塞