线程的概念和两种实现方法

一、线程概念

现代的操作系统都是多用户多进程分时操作系统,所以我们在使用操作系统时,可以一边听歌,一边下载,还可以聊天等等,事实上我们的操作系统同时还运行着很多后台进程,你可以打开window系统的任务管理器就可以看到很多进程在运行。
在这里插入图片描述
在往下学习之前,让我们先弄清楚什么是程序,进程和线程这几个概念。

1、程序:利用编程语言开发的一个工具软件, 静态的,在没有启动运行之前只是磁盘中的一个普通文件。

2、进程:程序启动之后就变成了进程,进程是在内存中运行的,具有一定的生命周期,如果程序运行解析,进程在内存中就会回收,生命周期也就结束了,当然程序是可以再次运行,重写变成进程。

3、线程:进程在运行过程中的执行走向,线索。线程是比进程更小的一个单位,一个进程可以有一个或多个线程的。

java程序启动运行时,就自动产生了一个线程,主函数main就是在这个线程上运行的,当不再产生新的线程时,程序就是单线程。到目前为止我们编写的所有的java程序都是单线程的,接下来我们要学习如何实现多线程的java程序。

二、线程的实现方法
1.单线程
我们新建一个类Stu1实现一个简单的循环。

public class Stu1 {
	public static void main(String []args) {
		//主线程
		for(int i=0;i<10;i++) {
			System.out.println("主线程:"+i);
		}
		System.out.println("主线程:死亡");
		
	}
}

运行结果:
在这里插入图片描述
2、通过继承Thread类实现第一个线程。新建一个Thread1类继承Thread类,并重写run方法,run方法就是线程的执行内容。实现代码如下:

public class Thread1 extends Thread{
    //线程体
    public void run(){
        for(int i=0;i<5;i++){
            System.out.println("线程1:"+i);
        }
        System.out.println("线程1:死亡");
    }
}

我们要启动这个线程不是调用run()方法,而是使用start()方法启动线程,线程启动后会自动执行run()方法。

修改上面的Stu1的main方法,启动这个线程。修改如下:

public static void main(String []args) {
		Thread1 thread1=new Thread1();
		thread1.start();//通过start启动线程1,它会自动执行run方法
		
		//主线程
		for(int i=0;i<5;i++) {
			System.out.println("主线程:"+i);
		}
		System.out.println("主线程:死亡");
		
	}

结果:某次运行结果如下:
某次运行结果
由输出可见,主线程和子线程之间是独立运行的,它们将会轮流的占用CPU,而那个线程会占有CPU是由操作系统决定的。所以我们看到多次运行这个程序时,每一次的输出可能都不一样。

**3、通过实现Runnable接口实现线程。**为了克服java单继承的限制,java提供了另外一种实现线程类的方式,就是实现Runnable接口,因为接口是可以同时实现多个接口的。同样需要实现run方法。实现代码如下:

public class Thread2 implements Runnable{
	@Override
	public void run() {
	//线程2
		for(int i=0;i<5;i++) {
			System.out.println("线程2:"+i);
		}
		System.out.println("线程2:死亡");
	}
	
	public static void main(String[]args) {
		//启动线程
		Thread t2=new Thread(new Thread2());
		t2.start();
		
		//主线程
		for(int i=0;i<5;i++) {
			System.out.println("主线程:"+i);
		}
		System.out.println("主线程:死亡");
	}
}

**4、其他的方法。**事实上面我们可以通过setPriority设置优先级别,当然设置优先级别也只是一个给操作系统一个建议,最后谁先占用CPU还是按照操作系统自己的算法。

另外我们也可以通过sleep()方法让线程休眠,这样他就不会占用CPU了。参考代码如下:

public class Thread2 implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println("线程2:"+i);
		}
		System.out.println("线程2:死亡");
	}
	
	public static void main(String[]args) {
		//启动线程
		Thread t2=new Thread(new Thread2());
		t2.start();
		
		//主线程休眠
		try {
			Thread.currentThread().sleep(2000);
		}catch(InterruptedException e){
			// TODO Auto-generated catch block
            e.printStackTrace();
		}
		
		//主线程
		for (int i = 0; i < 10; i++) {
            System.out.println("主线程:" + i);
        }
        System.out.println("主线程:死亡");
	}
}

运行上面的代码,我们发现主线程的循环要等待两秒后才输出,而线程2的优先级别是最高的。

三、java线程的状态
每个线程都有一个从初始状态到死亡状态的生命周期,其间根据业务流程经过就绪状态(runnable)、运行状态(runing)、阻塞状态(blocked),这些状态可以根据流行需要相互转换。线程状态转换示意图
在这里插入图片描述
0、初始状态跟其他Java对象一样用new语句创建的线程对象处于初始状态,此时仅被分配了内存。

1、就绪状态(Runnable)

当每个线程对象创建好后,通过调用其start()方法使得该线程就进入就绪状态,就绪状态的线程进入到JVM的可运行池中等待CPU的使用权,每个线程都可以通过设置其优先级以提高取得CPU的使用权的可能性。当然,CPU的使用权跟计算机的硬件分不开的,这体现在单CPU环境下跟多CPU(及单CPU多核)下处理是不一样的,因为同一时刻可以让几个线程占用不同的CPU。

2、运行状态

在JVM中就绪状态的线程取得CPU的使用权后,得以执行run()方法中定义的程序代码。只有处于就绪状态的线程才有机会转到运行状态。

3、阻塞状态(Blocked)

运行中的线程可以根据需要放弃占用的CPU而暂停运行,这是线程就处于阻塞状态,此时Jvm不再尝试给线程分配CPU使用机会。处于阻塞状态有三种情况:

1.位于Jvm线程等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,参见第20章的20.1.1节(同步代码块)。

2.位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中,参见第20章的20.2节(线程通信)。

3.其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求,就会进入这个状态。

4、死亡状态(Deaded)

当线程正常执行完run()方法中的代码,或者遇到异常未捕获造成中断,线程就会退出运行状态,转入死亡状态,结束其生命周期。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值