线程调度

上一篇文章是初步了解多线程,以及多线程的java实现,现在我们围绕线程状态的关系图,分析线程状态间的调度。




isalive()判断线程是否启动

package thread;
/**
 * 
 * 判断线程是否启动
 * @author shangwei
 *
 */
public class isalive implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<3;i++){
			System.out.println(Thread.currentThread().getName());
		}
	}
	
	public static void main(String[] args){
		isalive is = new isalive();
		Thread demo = new Thread(is);
		System.out.println("线程启动之前---"+demo.isAlive());
		demo.start();
		System.out.println("线程启动之后---"+demo.isAlive());
	}

}

在java中每次程序运行都会至少启动2个线程,一个是main线程,一个垃圾回收线程,每当使用java命令执行一个类的时候都会启动jvm,每一个jvm在操作系统中会生成一个进程。

我们看一下运行结果,分别出现了2种结果:

第一种:

线程启动之前---false

Thread-1

Thread-1

Thread-1

线程启动之后---false

第二种:

线程启动之前---false

线程启动之后---true

Thread-1

Thread-1

Thread-1


我们可以看出主线程可能在子线程结束之前结束,并且子线程不受影响,不会因为主线程的结束而结束。


join() 线程强制执行

package thread;
/**
 * join 指定的线程加入到当前线程
 * @author shangwei
 *
 */
public class joinTest implements Runnable{

	public static int a = 0;
	@Override
	public void run() {
		for(int k =0;k<5;k++)
		{
			a = a+1;
		}
		// TODO Auto-generated method stub
		
	}	
	public static void main(String[] args) throws Exception{
		
		Runnable r  = new joinTest();
		Thread t = new Thread(r);
		t.start();
		t.join();
		System.out.println(a);		
	}
}

请问程序的输出结果是5吗?答案是:有可能。其实你很难遇到输出5的时候,通常情况下都不是5。当然这也和机器有严重的关系。为什么呢?我的解释是 当主线程 main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行。因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);,这个时候得到的结果是a还没有被 改变的值0  。怎样才能让输出结果为5!其实很简单,join() 方法提供了这种功能。join() 方法,它能够使调用该方法的线程在此之前执行完毕。


源代码


/** 
     *  Waits at most <code>millis</code> milliseconds for this thread to   
     * die. A timeout of <code>0</code> means to wait forever.   
     */  
    //此处A timeout of 0 means to wait forever 字面意思是永远等待,其实是等到t结束后。  
    public final synchronized void join(long millis)    throws InterruptedException {  
        long base = System.currentTimeMillis();  
        long now = 0;  
  
        if (millis < 0) {  
            throw new IllegalArgumentException("timeout value is negative");  
        }  
          
        if (millis == 0) {  
            while (isAlive()) {  
                wait(0);  
            }  
        } else {  
            while (isAlive()) {  
                long delay = millis - now;  
                if (delay <= 0) {  
                    break;  
                }  
                wait(delay);  
                now = System.currentTimeMillis() - base;  
            }  
        }  
    }  

Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁

sleep()线程的休眠

package thread;

public class sleep implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i = 0;i<3;i++){
			try{
				Thread.sleep(2000);
			}catch (Exception e){
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+i);
		}
	}
	public static void main(String[] args){
		
		sleep s = new sleep();
		Thread demo = new Thread(s,"线程");
		demo.start();
				
	}

}


运行结果:结果每隔2s输出一个

线程0

线程1

线程2


interrupt()线程中断

interrupt 不会中断一个正在运行的线程,它的作用是在线程遇到阻塞的时候抛出一个中断信号,这样线程就得以退出阻塞的状态。如果线程被wait,join,sleep三种方法之一阻塞,那么它将收到一个中断一场,从而尽早的终结被阻塞的状态。

package thread;

public class interrupt implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("执行run方法");
		try {
			Thread.sleep(10000);
			System.out.println("线程休眠完成");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			System.out.println("休眠被打断");
			e.printStackTrace();
		}
		System.out.println("线程正常终止");
	}
	
	public static void main(String[] args){
		interrupt in = new interrupt();
		Thread t = new Thread(in,"线程");
		t.start();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		t.interrupt();//2s后中断线程
	}

}

运行结果:

执行run方法

休眠被打断

java.lang.InterruptedException: sleep interrupted

at java.lang.Thread.sleep(Native Method)

at thread.interrupt.run(interrupt.java:10)

at java.lang.Thread.run(Thread.java:695)

线程正常终止


优先级

java优先级是一个整数,其取值范围是1Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY)。

thread源代码里对NORM_PRIORITY(数值为5)的注释是‘线程的默认的优先级’

public final static int NORM_PRIORITY = 5;  

其实不然,默认的优先级是父线程的优先级,在init方法里,

  1. Thread parent = currentThread();  
  2. this.priority = parent.getPriority(); 

这里理解是因为java线程的主线程(main方法)的优先级默认是为NORM_PRIORITY,这样不主动设定优先级后,后续创建的线程的优先级也都是NORM_PRIORITY

  1. public static void main(String[] args) {  
  2.     System.out.println(Thread.currentThread().getPriority());  
  3. }  

执行结果是5


package thread;

public class priority implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		
		for(int i=0;i<10;i++){
			System.out.println(Thread.currentThread().getName()+"运行"+i);
		}
		
	}
	
	public static void main(String[] args){
		priority p = new priority();
		Thread t1 = new Thread(p,"A");
		Thread t2 = new Thread(p,"B");
		Thread t3 = new Thread(p,"C");
		t1.setPriority(8);
		t2.setPriority(2);
		t3.setPriority(6);
		t1.start();
		t2.start();
		t3.start();
	}
	
	

}

执行结果:

A运行0

A运行1

A运行2

A运行3

A运行4

A运行5

A运行6

A运行7

A运行8

B运行0

C运行0

A运行9

B运行1

C运行1

C运行2

C运行3

C运行4

C运行5

C运行6

C运行7

C运行8

C运行9

B运行2

B运行3

B运行4

B运行5

B运行6

B运行7

B运行8

B运行9



yield() 线程的礼让

package thread;

public class yield implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<5;++i){
			System.out.println(Thread.currentThread().getName()+"运行"+i);
			if(i ==3){
				System.out.println("线程礼让");
				Thread.currentThread().yield();
			}
		}
	}

	public static void main(String[] args){
		yield y = new yield();
		Thread t1= new Thread(y,"线程A");
		Thread t2= new Thread(y,"线程B");
		t1.start();
		t2.start();
	}
}


运行结果:

线程A运行0

线程A运行1

线程A运行2

线程A运行3

线程礼让

线程B运行0

线程B运行1

线程B运行2

线程B运行3

线程礼让

线程A运行4

线程B运行4



同步锁

还记得上一篇文章中的共享资源的案例吗?我们稍微改动下,加一个休眠时间

package thread;

public class runnable_share_4 implements Runnable {
	
	private int count = 5;
	
	public static void main(String[] args){
		runnable_share_4 h1 = new runnable_share_4();
		Thread t1 = new Thread(h1,"1号窗口");
		t1.start();
		Thread t2 = new Thread(h1,"2号窗口");
		t2.start();
		Thread t3 = new Thread(h1,"3号窗口");
		t3.start();
		
	}

	@Override
	public void run() {
		for(int i=0;i<10;++i){
			if(count >0){
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"count"+"正在卖"+count--);
			}
		}
		// TODO Auto-generated method stub
		
	}

}

运行结果:

3号窗口count正在卖5

2号窗口count正在卖4

1号窗口count正在卖4

1号窗口count正在卖3

2号窗口count正在卖1

3号窗口count正在卖2


 如果想解决这种问题,就需要使用同步,所谓同步就是同一个时间段只有一个线程运行,其他线程必须等到这个线程结束后才能继续执行。

采用同步的话,可以使用同步代码块和同步方法两种方式


[同步代码块]

语法格式:

synchronized(同步对象){

 //需要同步的代码

}

但是一般都把当前对象this作为同步对象。

package thread;

public class synchronized_块 implements Runnable {
	
	private int count = 5;
	
	public static void main(String[] args){
		synchronized_块 h1 = new synchronized_块();
		Thread t1 = new Thread(h1,"1号窗口");
		t1.start();
		Thread t2 = new Thread(h1,"2号窗口");
		t2.start();
		Thread t3 = new Thread(h1,"3号窗口");
		t3.start();
		
	}

	@Override
	public void run() {
		for(int i=0;i<10;++i){
			synchronized(this){
			if(count >0){
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"count"+"正在卖"+count--);
			}
			}
		}
		// TODO Auto-generated method stub
		
	}

}

结果如下:

1号窗口count正在卖5

1号窗口count正在卖4

1号窗口count正在卖3

1号窗口count正在卖2

1号窗口count正在卖1


【同步方法】

也可以采用同步方法。

语法格式为synchronized 方法返回类型方法名(参数列表){

    // 其他代码

}


package thread;

public class synchronized_方法 implements Runnable {
	
	private int count = 5;
	
	public static void main(String[] args){
		synchronized_方法 h1 = new synchronized_方法();
		Thread t1 = new Thread(h1,"1号窗口");
		t1.start();
		Thread t2 = new Thread(h1,"2号窗口");
		t2.start();
		Thread t3 = new Thread(h1,"3号窗口");
		t3.start();
		
	}
	
	public synchronized void sale (){
		if(count >0){
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"count"+"正在卖"+count--);
		}
		
	}

	@Override
	public void run() {
		for(int i=0;i<10;++i){
			sale();
		}
		// TODO Auto-generated method stub
		
	}

}


结果如下:

1号窗口count正在卖5

1号窗口count正在卖4

1号窗口count正在卖3

1号窗口count正在卖2

1号窗口count正在卖1



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值