从零开始java多线程到分布式锁(二):多线程的之间的线程协作

一:java多线程的JVM运行模型

  首先当一个单线程转变成一个多线程运作时,我们需要对JVM的内存模型有一些基本的了解。首先我们来看一下在多线程的情况下JVM如何运行线程方式,如图所示:

                      

  网上很多对这个运行模型讲解的不是很透彻,这里我们做一个简单说明,主要分为以下几步:

(1)每一个线程复制出一个内存副本(图中以共享变量为主),也就是缓存出一个应用层次的副本,每一个线程都是在本线程             的副本中进行操作,避免每一个线程都要到内存中操作,占用内存空间(这是多线程的优势,也是产生多线程的问题的高             发区)。

(2)每一个线程完成或者在一个时间点同步副本至主内存中。

 

二:多线程的线程协作

  从上面的介绍可以看出每一个线程多事由自己独立的运存副本,在没有同步之前线程与线程之间是独立的。那么我们如何在多个线程运行时去调度不同线程的状态(注:这里的调度区别于在A线程中控制B线程的运行状态,这里涉及到java的NIO编程模式-Netty)。java提供了2种方式:一是Object的wait()等方法和基于线程的sleep()方法等、

  首先在谈到这些方法之前提到一个很多面试会遇到的问题:为什么wait()是Object的方法,而不是线程的方法?希望带着这个问题去往下阅读。

(1)Object的wait方法

    这个方法是指当前线程进入阻赛状态即线程挂起,先上一段代码看一下吧。

package test;

/**
 * 多线程的Object的wait方法
 * @author monxz
 *
 */
public class WaitMethod {
	
	public void  waitTest(){
		System.out.println("======wait开始==========");
		 try {
			            wait(1000);
			  } catch (InterruptedException e) {
			       e.printStackTrace();
		   }
		 System.out.println("======wait结束==========");
	}
	
	public static void main(String[] args) {
		WaitMethod  WaitMethod =new WaitMethod();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				WaitMethod.waitTest();
				
			}
		}).start();
	}
}

  然而,这段运行结果尽然抛出异常,如下图所示:百度了一下,该异常的主要就是说没有获取到对象的Monitor锁造成的,java对于这种异常就是在方法添加synchronized关键字来改善,这里代码就是不上传(在waitTest()上添加该关键字)

             

(2)Object的notify/notifyAll()方法

  该方法主要是针对(1)中的线程进入阻赛状态下的线程花旗,前者唤醒单个线程,或者唤醒全部休眠线程。这个方法主要就是针也是基于Object对象的Monitor所实现的。具体代码就不用上传了。

(3)Thread的sleep()方法

  sleep方法主要是让方法进入一个线程暂停,这里上一个实例代码:

package test;

/**
 * 多线程的Thread的sleep方法
 * @author monxz
 *
 */
public class sleepMethod {
	
	public   void  sleepTest(){
		System.out.println("======wait开始==========");
		
		System.out.println("======wait结束==========");
	}
	
	public static void main(String[] args) {
		sleepMethod  WaitMethod =new sleepMethod();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				WaitMethod.sleepTest();
				
			}
		}).run();
		
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			
			e.printStackTrace();
		}
		
		
		System.out.println("=======over===========");
	}
}

  其实,很明显可以看出来,sleep()是在一个线程开始或者结束进行调用方法的这里明显就区别于wait方法了(即调用wait方法必须依赖于Object对象及其方法,未定义一个对象是无法使用wait()方法的。而sleep方法只依赖于Thread,即使没有对象只要使用Thread去调用即可),下面该出一个说明代码:

package test;

/**
 * 多线程的Thread的sleep方法
 * @author monxz
 *
 */
public class sleepMethod2 {
	
	public   void  sleepTest(){
		System.out.println("======wait开始==========");
		
		System.out.println("======wait结束==========");
	}
	
	public static void main(String[] args) {
		System.out.println("=======begin===========");
		
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			
			e.printStackTrace();
		}
		
		
		
		
		
		System.out.println("=======over===========");
	}
}

(3)Thread的yield()方法

  这个方法是指让多个线程进行交替运行,先上一个代码吧:

package test;

/**
 * 多线程的Thread的sleep方法
 * @author monxz
 *
 */
public class yieldMethod implements Runnable{
	
	@Override
	public void run() {
		for(int i = 0 ;i<5 ; i++ ){
			System.out.println(Thread.currentThread().getName() +"线程运行结果:"+ i );
			Thread.yield();
		}
		
	}
	
	public static void main(String[] args) {
		yieldMethod  yieldMethod =new yieldMethod();
		Thread  t1 = new Thread(yieldMethod, "线程一");
		Thread  t2 =new Thread(yieldMethod,"线程二");
		t1.start();;
		t2.start();;
	}

	
}

    这段代码理想运行结果是应该如下图所示,但是很尴尬的是还会出现以下的状态,后来百度了以下原因是,虽然该方法允许多个线程交替运行,但是这个交替过程不可控,也就是出现以下救过都是正确的,所以一般这个方法很少用,如果要用一定要控制好外部条件:

  

(4)Thread的Join方法 

  Join()方法就是讲多线程的方法转成同步方法,从一开始的JVM图中可以看出一般情况下,多线程的运行是互不影响的,那么如果需要将互不影响改为同步,也就是说A线程一定是在B线程结束才运行的,那么A线程运行结果同步到主内存,然后B线程复制副本再运行等等,那么就必须依赖于同步锁关键字,这里查看join的源码发现join方法实际上是用wait()来实现的。join方法有一个学名,父线程等待子线程运行结束在运行。

 

三:Object方法和Thread方法的区别于总结

(1)Object方法需要依赖于对象的Monitor锁实现,所以必须要先定义一个对象。而Thread方法可以直接使用线程Thread来调用方法,这以很好的回答了在本文中间提出的问题了。

(2)Object方法的wait方法是会释放对象的Monitor对象锁的,而Thread并不会。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值