900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 【Java_多线程并发编程】基础篇—线程状态及实现多线程的两种方式

【Java_多线程并发编程】基础篇—线程状态及实现多线程的两种方式

时间:2022-02-03 14:11:12

相关推荐

【Java_多线程并发编程】基础篇—线程状态及实现多线程的两种方式

1.Java多线程的概念

同一时间段内,位于同一处理器上多个已开启但未执行完毕的线程叫做多线程。他们通过轮寻获得CPU处理时间,从而在宏观上构成一种同时在执行的假象,实质上在任意时刻只有一个线程获得CPU资源执行,这种方式叫做并发。

线程状态图

说明

线程共包括以下5种状态。

1.新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。

2.就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。

3.运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。

4.阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。线程阻塞的情况分三种:

(01)等待阻塞-- 通过调用线程的wait()方法,让线程等待某工作的完成。

(02)同步阻塞-- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。

(03)其他阻塞-- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

5.死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

这5种状态涉及到的内容包括Object类, Thread和synchronized关键字。这些内容我们会在后面的章节中逐个进行学习。

Object类,定义了wait(), notify(), notifyAll()等休眠/唤醒函数。

Thread类,定义了一些列的线程操作函数。例如,sleep()休眠函数, interrupt()中断函数, getName()获取线程名称等。

synchronized,是关键字;它区分为synchronized代码块和synchronized方法。synchronized的作用是让线程获取对象的同步锁。

在后面详细介绍wait(),notify()等方法时,我们会分析为什么“wait(), notify()等方法要定义在Object类,而不是Thread类中”。

2. 实现多线程的两种常用方式

第一种方式:直接以继承了Thread的子类new出一个线程对象。

第二种方式:以实现了Runnable接口的对象作为Thread构造方法的实参,由Thread类new出一个线程对象。

之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程。关于线程池的内容,我们以后会详细介绍。

2.1 Thread和Runnable简介

Runnable是一个接口,该接口中只包含了一个run()方法。它的定义如下:

public interface Runnable {public abstract void run();}

Runnable的作用,实现多线程。我们可以定义一个类A实现Runnable接口;然后,通过new Thread(new A())等方式新建线程。

Thread是一个类。Thread本身就实现了Runnable接口。它的声明如下:

public class Thread implements Runnable {}

Thread的作用,实现多线程。

Thread和Runnable的异同点:

Thread 和 Runnable 的相同点:都是“多线程的实现方式”。

Thread和 Runnable 的不同点:Thread 是类,而Runnable是接口;Thread本身是实现了Runnable接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。

此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。

通常,建议通过“Runnable”实现多线程!

2.2 Thread实现多线程示例

// ThreadTest.java 源码class MyThread extends Thread{ private int ticket=10; public void run(){for(int i=0;i<20;i++){ if(this.ticket>0){System.out.println(this.getName()+" 卖票:ticket"+this.ticket--); } } } }; public class ThreadTest { public static void main(String[] args) { // 启动3个线程t1,t2,t3;每个线程各卖10张票! MyThread t1=new MyThread(); MyThread t2=new MyThread(); MyThread t3=new MyThread(); t1.start(); t2.start(); t3.start(); } }

运行结果

Thread-0 卖票:ticket10Thread-1 卖票:ticket10Thread-2 卖票:ticket10Thread-1 卖票:ticket9Thread-0 卖票:ticket9Thread-1 卖票:ticket8 Thread-2 卖票:ticket9 Thread-1 卖票:ticket7 Thread-0 卖票:ticket8 Thread-1 卖票:ticket6 Thread-2 卖票:ticket8 Thread-1 卖票:ticket5 Thread-0 卖票:ticket7 Thread-1 卖票:ticket4 Thread-2 卖票:ticket7 Thread-1 卖票:ticket3 Thread-0 卖票:ticket6 Thread-1 卖票:ticket2 Thread-2 卖票:ticket6 Thread-2 卖票:ticket5 Thread-2 卖票:ticket4 Thread-1 卖票:ticket1 Thread-0 卖票:ticket5 Thread-2 卖票:ticket3 Thread-0 卖票:ticket4 Thread-2 卖票:ticket2 Thread-0 卖票:ticket3 Thread-2 卖票:ticket1 Thread-0 卖票:ticket2 Thread-0 卖票:ticket1

结果说明

(01) MyThread继承于Thread,它是自定义个线程。每个MyThread都会卖出10张票。

(02) 主线程main创建并启动3个MyThread子线程。每个子线程都各自卖出了10张票。

2.3 Runnable接口实现多线程的示例

// RunnableTest.java 源码class MyThread implements Runnable{ private int ticket=10; public void run(){for(int i=0;i<20;i++){ if(this.ticket>0){System.out.println(Thread.currentThread().getName()+" 卖票:ticket"+this.ticket--);}}} }; public class RunnableTest { public static void main(String[] args) { MyThread mt=new MyThread();// 启动3个线程t1,t2,t3(它们共用一个Runnable对象),这3个线程一共卖10张票!Thread t1=new Thread(mt);Thread t2=new Thread(mt);Thread t3=new Thread(mt);t1.start();t2.start();t3.start();} }

运行结果

Thread-0 卖票:ticket10Thread-2 卖票:ticket8Thread-1 卖票:ticket9Thread-2 卖票:ticket6Thread-0 卖票:ticket7Thread-2 卖票:ticket4Thread-1 卖票:ticket5Thread-2 卖票:ticket2Thread-0 卖票:ticket3Thread-1 卖票:ticket1

结果说明:

(01) 由于t1、t2、t3这三个线程都是由Thread类以mt对象作为参数new出来的,所以他们共享对象mt,因此三个线程一共卖出了10张票。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。