《黑马程序员》 线程的互斥与同步

------- android培训java培训、期待与您交流! ----------
public class TraditionalThreadCommuncationTest {
	/**
	 * 子线程循环10次,接着主线程循环100,接着又回到子线程循环10次, 接着再回到主线程又循环100,如此循环50次,请写出程序。
	 * 我们先来实现这样的效果: 先实现2个线程都执行语句。 一个线程在执行的时候其它的线程不会去打断他的执行。
	 * 我们没有使用互斥。主线程在执行的时候,还没有执行完就被子线程给打断了
	 * 
	 * main thread sequence of:1,loop of:1 main thread sequence of:2,loop of:1
	 * main thread sequence of:3,loop of:1 sub thread sequence of:1,loop of:1
	 * sub thread sequence of:2,loop of:1 sub thread sequence of:3,loop of:1
	 * 
	 * 我们要让它们产生互斥。我们可以使用synchronized(.class) 我们是把线程要执行的任务的代码给保护起来。让它们互斥。 for
	 * (int i = 1; i <= 10; i++) { for (int j = 1; j <= 5; j++) {
	 * System.out.println("sub thread sequence of:" + j+",loop of:"+i); } }
	 * 其实我们真正要保护起来的是内循环里面的代码。因为外循环是把内循环中的代码给重复执行了50次
	 * 我们打印信息是由内循环控制的。即子线程打印1-5的数字,在子线程没有打印完之后,其它的线程是不能打印的 所以要把这个循环给保护起来。
	 * 
	 * 我们在这里做互斥是为了我们有一个线程在执行这段代码的时候其它的线程是不可以来执行这段代码。即其它的线程 不能打断当前线程的任务的执行。
	 * 
	 * 我们使用了这个发现我们的代码其实写的并不好
	 * 
	 * 我们使用下面的原理分析一下: 像我们在登录网站的时候,在浏览器上输入用户名和密码,网站会给我们提供一个记录密码,2星期自动登录的功能。
	 * 这个时候其实是用户在登录的时候使用到了一个Servlet,服务器向浏览器生成了一个加密后的cookie.因为cookie
	 * 在硬盘上,别人就可以看到用户名和密码了。所以在生成的时候对cookie的密码进行加密。下次用户在登 录的 时候,
	 * 访问到了相同服务器上的相同的资源和其它的数据的时候,在登录的时候,就会有一个flter进行拦截。
	 * 这个filter的内部就是解密cookie,校验信息。验证成功之后自动登录。
	 * 其实在服务器的Servlet内部就有一个生成加密后的cookie的方法。在filter的内部就是有一个解密cookie的方法
	 * 但是这个方法并在这两个类身上并不合适。我们应该这么做,把相关联的数据归到同一个类上去。即创建一个新的类
	 * 然后把这两个方法放到新的类身上。然后在Servlet和filter中引用新的类身上的方法。
	 * 其实高类聚就是把相关联的数据归到同一个类身上,这样便于以后的维护。在类身上改了。Servlet和filter里面的
	 * 数据自动就更改了。所谓相关联的数据,因为这里的加密和解密的方法使用到了相同的公式。所以它们是相关联的公式
	 * ,而我们使用到了相同的数据,及我们进行互斥也是相关联的数据。所以都可以使用高类聚来操作。
	 * 
	 * 我们要想让它们交替执行任务就要让子线程执行完任务之后通知主线程执行任务。主线程执行完任务之后让通知主线程执行任务。(使用线程的通讯)
	 * 但我们子线程在执行代码的时候,主线程不去打断子线程的代码的执行。反之也是如此。
	 */
	public static void main(String[] args) {
		final Business busi = new Business();
		// 子线程
		new Thread(new Runnable() {

			@Override
			public void run() {
				for (int i = 1; i <= 50; i++) {
					// synchronized(ThreadTest.class){
					// for (int j = 1; j <= 5; j++) {
					// System.out.println("sub thread sequence of:" +
					// j+",loop of:"+i);
					// }
					// }\
					busi.sub(i); // 调用相关联的类身上的方法
				}
			}
		}).start();
		// 主线程
		for (int i = 1; i <= 50; i++) {
			// synchronized(ThreadTest.class){
			// for (int j = 1; j <= 5; j++) {
			// System.out.println("main thread sequence of:" + j+",loop of:"+i);
			// }
			// }
			busi.main(i); // 调用相关联的类身上的方法
		}
	}
}

/**
 * 我们使用高类聚的方式来改写这个代码 所谓的高类聚就是把相关联的数据给归到同一个类身上。 然后哪个地方需要使用相关联的数据。直接调用这个类身上的方法就可以了
 * 这样便于程序的维护 我们以后在维护的时候直接去这个类上进行维护即可。不用再去修改Servlet和filter身上的代码了。
 * 
 * @author zzg
 * 
 */
class Business {
	private boolean bShouldSub = true; // 设置默认是子线程执行任务
	//因为我们要让子线程先执行

	// synchronized使用的监视器对象是this
	public synchronized void sub(int i) {
		// 因为当其它的线程在执行任务的时候,cpu随机切换到这个方法上的时候
		// 我们是没有办法判断不让线程进入到这个方法的。
		// 但是我们可以使用一个变量来处理。
		// 我们使用一个变量,如果是当前的变量,就执行任务,如果不是,就让它处于等待的状态
		if (!bShouldSub) {
			// 如果当前的线程不是子线程在执行任务
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} // 就让它处于等待的状态
		}
		// 子线程要执行的任务代码
		for (int j = 1; j <= 10; j++) {
			System.out.println("sub thread sequence of:" + j + ",loop of:" + i);
		}
		// 子线程在执行完毕之后就把变量给设置成false了,这样当cpu再次切换到这个方法上的时候,就
		// 执行了if判断语句。条件满足子线程就等待了
		bShouldSub = false;
		// 把变量的值给修改。这样cpu切换到了主线程的时候,主线程就可以执行线程任务了

		// 子线程在执行的时候,主线程中的条件是满足的,条件是如果子线程在执行任务,主线程就处于等待
		// 所以子线程在执行完毕之后,除了要把变量给修改成false之外,还要唤醒处于等待状态的线程。因为这里
		// 只有一个所以唤醒的就是主线程
		this.notify();
	}

	public synchronized void main(int i) {
		if (bShouldSub) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		for (int j = 1; j <= 100; j++) {
			System.out
					.println("main thread sequence of:" + j + ",loop of:" + i);
		}
		bShouldSub = true; // 把变量的值给修改。这样cpu切换到了子线程的时候,子线程就可以执行线程任务了
		this.notify();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值