java多线程初步理解

 

      也许我们经常做的事就是一边聊QQ一边听音乐,有的还一边玩游戏,这一切都是多任务实现的。而java语言使用多线程实现了一个程序中的多个任务同时运行。

      那到底是不是同时执行多线程呢?显然不是,CPU一次只能然一个线程执行,由于线程之间切换速度很快,所以在我们看来是同时执行的。

 

java中如何实现多线程:

      1.继承Thread类创建多线程。

      2.实现Runnable接口创建多线程。

 

      继承Thread类,重写run()方法是实现多线程的方式之一,Thread类本身就实现了Runnable接口。

如下例继承Thread类:

public class ThreadTest extends Thread{
	public void run(){
		while(true){
			String name = Thread.currentThread().getName();
			sayHello(name);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public void sayHello(String name){
		System.out.println(name+"说hello");
	}
	public static void main(String [] agrs){
		ThreadTest tt1 = new ThreadTest();
		ThreadTest tt2 = new ThreadTest();
		tt1.start();
		tt2.start();
	}
}

 

我的运行结果(每个人的运行结果都会不同):

Thread-0说hello
Thread-1说hello
Thread-1说hello
Thread-0说hello
Thread-1说hello
Thread-0说hello
Thread-1说hello
Thread-0说hello

 

      可以看出线程是一个一个执行的,并且不是按顺序执行的,红色标记的地方说明。cpu为每个线程分配了时间片,哪个线程得到了CPU,哪个线程就得到执行,这个在后面再说明。

 

      实现Runnable接口,实现run()方法来创建多线程,如下例:

public class ThreadTest implements Runnable{
	public void run() {
		while(true){
			String name = Thread.currentThread().getName();
			sayHello(name);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public void sayHello(String name){
		System.out.println(name+"说hello");
	}
	public static void main(String [] agrs){
		Runnable r = new ThreadTest();
		Thread thread1 = new Thread(r);
		Thread thread2 = new Thread(r);
		thread1.start();
		thread2.start();
	}
}

      这里只是创建线程对象有稍微的区别。

 

      那么他们之间有什么区别?甚至有的人问哪个更好?因为我就这么问过,但是在网上找到的答案基本都很片面,只找到了一个说的比较好,还需要时间研究研究。我列出来大家看看:

      1.适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设计思想。

      2.可以避免由于java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。

      3.有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程可以操作相同的数据,与它们的代码无关。当共享访问相同的对象时,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例

 

      那么实现多线程都是对run()方法重写,为什么不是直接调用run()方法而是调用start()方法呢?这里我们来看看run()和start()方法的区别。

start():

      通过调用start()方法来启动线程,此时线程处于就绪状态,一旦得到CPU时间片就执行run()方法,方法run()称为线程体,它包含了要执行这个线程的内容,当run()方法运行结束,线程随即终止。

run():

      run()方法只是Thread类的一个普通方法,如果直接调用run()方法,程序中只有主线程这一个线程,执行路径只有一条,要这个方法执行完才能执行下面的代码,这就没达到多线程的目的。

 

继续看如上例子,如果是:

      thread1.run();
         thread2.run();

那么运行结果为:

main说hello
main说hello
main说hello
main说hello
main说hello
main说hello
main说hello

 

      main就是我们一直以来接触的程序的入口(主方法),其实它本身就是一个线程,并且是主线程。 

 

线程的生命周期

      线程具有生命周期,包含3个状态,使用线程实例调用start()方法之前,线程处于出生状态,当调用start()方法后,线程就处于就绪状态,当线程得到系统资源后进入运行状态,当时间片结束线程又回到就绪状态,继续等待资源。

 

      而在线程执行过程中,线程又可能转入等待,睡眠,阻塞或者死亡状态

 

      1.线程在执行过程中调用wait()方法进入等待状态,这时线程释放持有的资源,必须采用notify()或者notifyAll()方法来唤醒该进程或者被别的对象调用interrupt()方法打断,这个方法会抛出一个InterruptedException异常,这个异常如果不捕获处理,线程就会异常终止,当线程被唤醒后,再次进入就绪状态,等待资源。

      2.线程在执行过程中调用sleep()方法,进入睡眠状态,这个过程线程不会释放持有的资源,待睡眠时间完后即进入就绪状态,不会立即进入执行状态,因为线程调度机制恢复线程的运行也需要时间。当然睡眠状态也会被interrupt(0方法打断,效果和wait()一样。

      3.线程执行过程中,因为某些原因而使其停止执行。当线程阻塞后,别的贤臣就有机会执行,当线程阻塞被解除后进入就绪状态,等待被调度。

       阻塞原因有:

        a.线程调用sleep()方法放弃CPU时间片。

        b.线程调用wait()方法,等待别的线程来唤醒它。

        c.线程调用阻塞IO方法,方法返回前处于阻塞状态。(IO后面会分析)

        d.线程执行需要资源,在执行过程中,某些资源被别的线程持有,则该线程会处于阻塞状态来等待资源的获取。

        e.程序调用suspend()方法将该线程挂起,该方法容易产生死锁。

      4.线程进入死亡状态也是有原因的。

       死亡原因:

        a.线程执行完run()方法进入死亡状态。

        b.线程通过某种方式终止线程使其进入死亡状态(接下来分析)。

        c.线程抛出未捕获的线程使线程异常终止。

 

终止线程

      在早期的JDK中提供了stop()方法来终止线程,但是新版本不建议使用,提倡用布尔标记控制循环的停止来达到终止线程的目的。

      1.在循环体中,通过条件判断,符合条件的就break;跳出循环,终止线程。

      2.循环条件不要写成true,而是手动控制循环条件的false来达到终止线程的目的。

 

线程的调度

      1.线程执行前,通过优先级来达到线程调度的目的,优先级高的线程优先得到CPU执行。线程的优先级可以在程序中表明该线程的重要级,学过操作系统的都明白有很多的调度算法,这里不细说了。

      2.线程执行过程中,可以通过join()方法来调度线程,比如:

threadA = new Thread(new Runnable(){
	public void run() {
		for(int i = 0;i<=100;i++){
			if(i >= 50){
				threadB.join();
			}
		}
	}
});

      显然在线程A执行时,当i=50的时候,就会执行线程B,直到线程B执行完,线程A才会继续执行,这样也能达到线程调度的目的。

 

线程安全

      在多线程中,说到什么最重要,要属线程安全当之无愧,引入多线程的目的就是对大量任务进行有序的管理,通过多个任务混合使用,可以更有效的利用计算机的资源

      使用多线程,会发生两个以上的线程抢占资源的问题,必须防止资源访问的冲突。java提供线程同步机制可以防止资源访问的冲突(下篇分析)。

 

      欲知后事如何,请看下集。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值