java 多线程学习笔记之 线程实现(线程阻塞)解析

不点 阅读:220 2021-03-31 22:41:21 评论:0

java 实现线程方法主要分为两种方法:一种是继承:java.lang.Thread, 另一种实现java.lang.Runnable接口。


对于直接继承Thread 的类来说,代码大致框架是:

public class MyThread extends Thread{ 
 
         //覆写run()方法 
         public void run(){ 
                   //other code   
         } 
}


对于实现Runnabel 接口来说,代码大致框架是:

public class MyRunnable implements Runnable{ 
 
         //实现run() 方法 
         public void run(){ 
                   //other code 
          } 
 
}

线程状态

新生状态(New): 当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(not alive);

         就绪状态(Preper): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态; 此时线程是活着的(alive);

   运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);

  阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)

死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thready已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)。



相关见解:

1、程序通过Thread t = new Thread(),调用t.start()启动一个线程,使该线程进入可运行(Runnable)的状态。

2、JVM去调度(Scheduler) 在可运行状态(Runnable)下的线程,使该线程处于运行 (Running) 状态,由于JVM的调度会出现不可控性,即不是优先级高的先被调用,可能先调用,也可能后调用的的情况。(并不依赖优先级

相关演示代码:

package com.example.main; 
 
import com.examplex.threadstate.MyThread; 
 
public class TestMain { 
 
	/** 
	 * @param args 
	 */ 
	public static void main(String[] args) { 
		// TODO Auto-generated method stub 
		MyThread thread1 = new MyThread("线程一"); 
		MyThread thread2 = new MyThread("线程二"); 
		MyThread thread3 = new MyThread("线程三"); 
		MyThread thread4 = new MyThread("线程四"); 
 
		// 测试线程等级 
		thread1.setPriority(Thread.MAX_PRIORITY); 
		thread2.setPriority(Thread.MIN_PRIORITY); 
		thread3.setPriority(Thread.NORM_PRIORITY); 
		thread4.setPriority(Thread.NORM_PRIORITY); 
 
		thread1.start(); 
		thread2.start(); 
		thread3.start(); 
		thread4.start(); 
 
	} 
 
} 
package com.examplex.threadstate; 
 
public class MyThread extends Thread { 
	// 线程名称 
	private String threadname; 
 
	public String getThreadname() { 
		return threadname; 
	} 
 
	public void setThreadname(String threadname) { 
		this.threadname = threadname; 
	} 
 
	public MyThread(String threadname) { 
		this.threadname = threadname; 
	} 
 
	@Override 
	public void run() { 
		// TODO Auto-generated method stub 
		System.out.println("我是自定义线程" + this.threadname); 
	} 
 
} 

3、线程 运行状态 (Running) 下,调用礼让 yield() 方法,可以使线程回到可运行状态 (Runnable) 下,等待 JVM 的再次调度(让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中)

结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。
相关测试代码:

package com.examplex.threadstate; 
 
public class MyRunnable implements Runnable { 
	private String runnablename; 
 
	public String getRunnablename() { 
		return runnablename; 
	} 
 
	public void setRunnablename(String runnablename) { 
		this.runnablename = runnablename; 
	} 
 
	public MyRunnable(String runnablename) { 
		this.runnablename = runnablename; 
	} 
 
	@Override 
	public void run() { 
 
		System.out.println("我是自定义线程:" + this.runnablename + "已獲得JVM調用"); 
		System.out.println("我是自定义线程:" + this.runnablename); 
 
	} 
 
} 

package com.examplex.threadstate; 
 
public class MyThread extends Thread { 
	// 线程名称 
	private String threadname; 
 
	public String getThreadname() { 
		return threadname; 
	} 
 
	public void setThreadname(String threadname) { 
		this.threadname = threadname; 
	} 
 
	public MyThread(String threadname) { 
		this.threadname = threadname; 
	} 
 
	@Override 
	public void run() { 
		// TODO Auto-generated method stub 
		System.out.println("我是自定义线程:" + this.threadname + "已獲得JVM調用"); 
		yield(); 
		System.out.println("我是自定义线程:" + this.threadname); 
	} 
 
} 
package com.example.main; 
 
import com.examplex.threadstate.MyRunnable; 
import com.examplex.threadstate.MyThread; 
 
public class TestMain { 
 
	/** 
	 * @param args 
	 */ 
	public static void main(String[] args) { 
		// TODO Auto-generated method stub 
		MyThread thread1 = new MyThread("线程一"); 
		MyRunnable thread2 = new MyRunnable("線程二"); 
		Thread thread = new Thread(thread2); 
		// 設置線程優先級 
		thread1.setPriority(Thread.MAX_PRIORITY); 
 
		// 测试線程yield方法 
		thread1.start(); 
		thread.start(); 
 
	} 
 
} 
相关截图:


4、线程在Running的过程中可能会遇到阻塞(Blocked)情况
①.调用join()sleep()方法,sleep()时间结束或被打断,join()中断都会回到Runnable状态,等待JVM的调度。

相关测试代码:

package com.examplex.threadstate; 
 
public class MyRunnable implements Runnable { 
	private String runnablename; 
 
	public String getRunnablename() { 
		return runnablename; 
	} 
 
	public void setRunnablename(String runnablename) { 
		this.runnablename = runnablename; 
	} 
 
	public MyRunnable(String runnablename) { 
		this.runnablename = runnablename; 
	} 
 
	@Override 
	public void run() { 
 
		System.out.println("我是自定义线程:" + this.runnablename + "已獲得JVM調用");		 
		System.out.println("我是自定义线程:" + this.runnablename); 
 
	} 
 
} 
package com.examplex.threadstate; 
 
public class MyThread extends Thread { 
	// 线程名称 
	private String threadname; 
 
	public String getThreadname() { 
		return threadname; 
	} 
 
	public void setThreadname(String threadname) { 
		this.threadname = threadname; 
	} 
 
	public MyThread(String threadname) { 
		this.threadname = threadname; 
	} 
 
	@Override 
	public void run()  { 
		// TODO Auto-generated method stub 
		System.out.println("我是自定义线程:" + this.threadname + "已獲得JVM調用");	 
		try{ 
		join(1000);  //此處也可為sleep()方法。 
		}catch(Exception e){ 
			e.printStackTrace(); 
		} 
		System.out.println("我是自定义线程:" + this.threadname); 
	} 
 
} 

package com.example.main; 
 
import com.examplex.threadstate.MyRunnable; 
import com.examplex.threadstate.MyThread; 
 
public class TestMain { 
 
	/** 
	 * @param args 
	 */ 
	public static void main(String[] args) { 
		// TODO Auto-generated method stub 
		MyThread thread1 = new MyThread("线程一"); 
		MyRunnable thread2 = new MyRunnable("線程二"); 
		Thread thread = new Thread(thread2); 
		// 設置線程優先級 
		thread1.setPriority(Thread.MAX_PRIORITY); 
 
		// 测试線程yield方法 
		thread1.start();		 
		thread.start(); 
 
	} 
 
} 
相关截图展示:



以上文件已经讲解了线程阻塞的实现方法【yield、sleep、join】和线程优先级问题,下一件多线程,主要讲解线程同步于互斥。




声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
排行榜
KIKK导航

KIKK导航

关注我们