java 多线程基础(一)——线程创建及五种状态

    最近在使用SOA的模式重构高校平台,在考试系统模块,期望使用上多线程,之前对多线程有过一些了解,不过具体的实现是在.net平台下的。虽然一年前接触过j2se的关于多线程的一些知识,但是感觉还是不够,于是最近,也算是在项目的驱动下,抽时间继续学习了一些java的多线程,这里拿出来分享一下。

一、多线程基础知识:

    对于多线程的基础知识,这里不做赘述,只是简单的交代两句。

  •     对于单核的cpu来说,多线程程序,本质也是单线程的,只是cpu在不停的切换。
  •     线程的优先级代表的是相关线程抢占cpu的频率。
  •    多线程编程不同于多核编程(多核编程控制cpu运行)。
  •    线程运行在进程中,可以看做是进程的一些个小单元。
二、关于线程的重点:
  • 线程的创建
  •  线程的五种状态
  •  线程同步
  •  线程间的通信
  •  生产者消费者问题
  •  jdk5.0以后对线程的优化
三、创建线程的两种方法:
  •  继承Thread类
/**
 * 方法一:
 * 	继承Thread类创建线程
 * @author LiMin
 *
 */
public class CreateThread extends Thread {
	private String name;
	public CreateThread(){
		
	}
	public CreateThread(String name){
		/*this.name=name;*/
		//调用父类的给线程命名的方法
		super(name);
		
	}
	public void run(){
		for(int x =0;x<60;x++){
			/*System.out.println(this.name+ " run -----"+ x);*/
			/*System.out.println(this.getName()+ " run -----"+ x);*/
			//使用Thread的静态方法获取线程名称Thread.currentThread().getName()是标准通用方式 
			/*System.out.println(Thread.currentThread().getName()+ " run -----"+ x);*/
			System.out.println((Thread.currentThread()==this)+"....."+this.getName()+ " run -----"+ x);
		}
	
	}
}

调用:
public class ThreadTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
	
		CreateThread t1 = new CreateThread("one----");
		CreateThread t2= new CreateThread("two+++++");
		
		t1.start();
		t2.start();
		
		
		for(int x =0;x<60;x++){
			System.out.println("main-----"+ x);
		}
	}

}

    程序比较简单,不多解释,重点注意:
  • 虚拟机定义主线程的main方法,Thread类的run方法,只是一个代码存储区。
  • start是底层的一个方法,调用了相应线程的run方法
  • run方法,并不是多线程的,只是一个对象的调用,主线程会等待这个对象的方法执行完后,再继续。
  • 系统会为每一个线程对象创建一个内存空间,所以,这里的for循环中的x都是一个独立的,不同的线程是互不影响的。
  • 除了售票以外,jvm还要调用dos的打印窗口,因为是多核的cpu 2号票已经出来了,但是还没有打印,这时候1号票也已经卖出了,结果先打印的是1号票,后打印1号票。



可以使用下面的程序验证run和start方法的区别
public class ThreadDemo {

	public static void main(String[] args){
		CreateThread d = new CreateThread();
		//开启线程,并执行该线程的run方法
		d.start();
		//仅仅是对象调用方法。而线程创建了,并没有运行。
	/*	d.run();*/
		 
		for(int x =0;x<60;x++){
			System.out.println("Hello word !-----"+ x);
		}
	}
}


  • 实现Runnable接口 (多个线程卖票

创建线程:
package TicketRunnable;

public class Ticket2 implements Runnable{ //extends Thread{	
	

	//如果是静态的话,所有的线程会共享这100张票
	/*private  static int  ticket =100;*/

	//如果不是静态的话,每一个线程对象都会创建这个ticket对象,也即每个线程拥有100张票卖。
	//这时候,如果还是采用继承Thread类的方法就不行了,需要使用实现Runnable接口创建线程
	private  int  ticket =1000;
	
	
	Object obj= new Object();	
	public void run() {
		
		//在这里声明的对象是无效的
		/*Object obj= new Object();	*/
		
		while(true){
			
			synchronized (obj) {
				if(ticket>0){	
					
					try {
						Thread.sleep(10);
						
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+".....sale : "+ ticket--);
					
				}
			}
			
		}
		
	} 

	

}

调用:
package TicketRunnable;

public class TicketDemo2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		Ticket2 t = new Ticket2();
		
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);
		Thread t4 = new Thread(t);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();		
		

	}

}

重点注意:

  • 将多线程要运行的代码存放在run方法中。
  • 通过Thread类建立线程对象。
  • 在创建线程对象的时候,就指定run方法所属的对象。

    将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数,这是因为:自定义的run方法所属的对象是Runnable接口的子类对象,所以,要让线程去指定对象的run方法,就必须明确run方法所属对象。

  • 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。


    对比:
    java是单类继承,使用Thread类继承,有很大的局限。使用Runnable,既不影响,你要开发的类的继承关系,同时也可以满足多线程的扩展,所以,提倡使用接口实现的方式。


四、线程的五种状态:
    一个线程可以有:创建、运行、临时阻塞、冻结(又分为睡眠和等待两种状态)、消亡五种状态。认识这五种状态是认识多线程的基础。看下图:

冻结:又分为睡眠和等待两种状态。

调用了start方法后,还在等待cpu来处理启动,这个时候的线程处于临时状态。

对应的一些常见的方法汇总成一个表格:

线程方法名称

是否释放同步锁

是否需要在同步的代码块中调用

方法是否已废弃

是否可以被中断

sleep()

wait()

suspend

 

 

 

resume()

 

 

 

join()

 

 



总结:
    这里使用具体的实例介绍了两种创建线程的方法,并给出了两种策略的优劣,最后得出,一般使用实现Runnable接口的方法。
    调用线程的不同方法会在线程的五种状态:创建、运行、临时阻塞、冻结之间切换。了解线程的方法和状态,是线程同步(锁:代码块、函数)以及线程间通信的基础。
    下一篇博客会介绍几种线程同步的策略以及相关的锁。

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值