多线程技术之所以诞生,其最根本的动因在于提高系统的资源利用率,以提升系统应对更复杂计算任务、更高强度的并发访问。
初次整理多线程技术从三个方面来整理
(1)、创建和启动线程;
(2)、管理线程的状态;
(3)、线程与Java对象之间的关系。
本篇博客——《线程的创建和启动线程》
内容目录:
一、线程简介
1 什么是线程
2 多线程的用途
2.1与用户的更加交互
2.2模拟同步动作
2.3利用多处理器
2.4在等待堵塞性动作期间完成其他任务
二、多线程应用开发
1 创建和启动线程
1.1 获取当前线程对象
1.2 构造和启动线程
1.3 线程的优先级
1.4 守护线程
2 Runnable接口和Thread基类
2.1实现Runnable接口
2.2继承Thread基类
正文
一、线程简介
1 什么是线程
现代操作系统在开始运行一个程序时,至少会创建一个进程少有一个运行中的线程(Thead).
2 多线程的用途
在某一些场合,引入多线程机制有利于提升程序的运行效果; 而在另一些场合,必须引入多线程机制才能满足需求。
2.1与用户的更加交互
在改善用户的使用体验方面的例子很多例如,我们在Window来面上复制个大文件,Windows会循环放映个纸从一个文件夹飞到另个文件夹的动面,放映动画和复制文件就是分处两个线程中,试想如果没有这段带有提示意味的功面“陷作“我们打发寂宽时光,我们就连是否复制充半都不知道。
2.2模拟同步动作
早期的计算机操作系统都是基于任务(相当于今天的进程来分配处理器运算资源的,而最终用户往往期望多任务同步并行,基于任务切换同步动作无疑不是最佳的途径。现代操作系统引入线程概念之后,任务被划分成了更细调度的线程,基于线程模拟同步动作,最终用户获得了多个任务并行处理的使用体验。
2.3利用多处理器
淡到多任务同步处理,自然就不得不提到当前逐渐成为主流的多处理器多核)计算机在单处理器计算机上,采用线程切换的手段模报同步动作,是否意味着在多处理器计算机上,就无须引入线程概念,便自然可以实现同步动作的效果了呢?
这里有两个误区:
(1):处理器的数量永远跟不上用户期待同时进行的任务的数量,
(2):人类永远不会觉得自己的计算机太快了,这是一条被反复印证的道理。人类社会越来越依赖计算机这就决定了计算机要面临的计算任务只会越来越复杂: 在图形界面出现之前,人们不会认为几百MB的外存储空间会不够使用,在多媒体时代之前,人们不会奢望在计算机上播放影音文件。
2.4在等待堵塞性动作期间完成其他任务
我们来思考个关于网络服务器工作原理的问题。假设存在个文件上传服务器,个用户上传个较大的文件时,另一个用户同时上传另个文件,如果文件上转服务器的开发者只懂得单线程编程的话,我们可以想象出后果: 后面那个用户的上传请求将一直搁置,直到等待超时。这是因为在服务器端,接受客户端连接请求和读取客户端字节流的过程旦运行在同个线程中,那么就意味着它们组成了堵塞性动作,除非读取完毕。否则上传服务器是不能再接入新的客户端的对于网络服务器来说。适合的做法是把接受连按请求和读取客户端输入字节流分为同不线程,这样接受连接请求的线程可以在核收到一个连接请求之后立刻将该请求转交给其他有处理请求的线程,而自身维续侦听是否有新的连接请求。主流的网络服务器,如Apache,采用的就是这种工作模式。
二、多线程应用开发
1 创建和启动线程
1.1 获取当前线程对象
首先明确一点,线程不是在代码中显式地创建之后才有,而是当应用程序启动之后便有一个默认存在的钱程,这个线程可以称之为主线程,无论对于主线程,还是之后创建的子线程,都可以通过Thread 类的ConcurrentThread()方法来获取当前线程对象。在获取线程对象之后,可以通过Thread 类的gtId()方法获取该线程在整个Java虚拟机中唯一的标识。
以下的代码行先获取当前的线程对象,维而获取当前线程对象的标识,
Thread.ConcurrentThread().getId() 线程ID 是一个的长整型数,在创建该线程时生成,线程ID是唯一的,井在线程的生命周期内保持不变,线程被终止后,该线程ID 可以被重新分配给其他的线程。
1.2 构造和启动线程
构造线程对象是通Thread类的构造方法完成的。Thread 类的构造方法分为3种。
其余稍后介绍。下面介绍Thead类的独立构造方法
Thread(): 构造一个线程,线程名由Java虚拟机根据线程命名规则指定。
Thread(String name) 构造个线程,以 mame 为线程名。
下面代码片段构造了两个线程,其中threadl 由Java虚报机根据线程命名规则指定.
thread2 命名为“MyThread”,
Thread thread1=newThread();
Thread thread2=mew Thead(“MyThread”);
以上构建的线程都是没有任何运逻辑的,也就是线程体为空。线程的线程体包含在Thead类的run方法中,可以在构建线程对象时重裁ru()方法,写入自定义的逻辑。构建线程之后启动线程的方法是利用Thread类的start()方法。对Thread类的run()和start()方法说明如下:
void ran(): 本方法中的逻辑为线程体。如果在构建线程时没有重载run0方法,则线程体为空: 如果线程系根据传入的jalang.Runnable对象而构建,则以该Runabhe对象的run()方法为线程体。
“void start():启动线程,开始执行线程对象的run()方法。
以下的代码片段构建了thread1、thread2.thread3共3 个线程对象,其中thread3系重载了rum()方法,在线程体中打印出“线程3 开始运行.”字样。然后分别启动3个线程,因为hread1 和thread2的线程体均为空,所以没有任何运行效果。接下来打印3个线程的标
识和名称:
public class CreateThread
{
public static void main(String[] args)
{
Thread thread1=new Thread();
Thread thread2=new Thread("MyThread");
Thread thread3=new Thread()
{
public void run()
{
System.out.println("线程3开始运行...");
}
};
thread1.start();
thread2.start();
thread3.start();
System.out.println("线程1的ID是:"+thread1.getId());
System.out.println("线程2的ID是:"+thread2.getId());
System.out.println("线程3的ID是:"+thread3.getId());
System.out.println("线程1的名称是:"+thread1.getName());
System.out.println("线程2的名称是:"+thread2.getName());
System.out.println("线程3的名称是:"+thread3.getName());
}
}
运行结果如下图
1.3 线程的优先级
为了区分个线程对于操作系统和用户的重要性。Java定义了线程的优先级策略,例先级高的处于就绪状态的线程更有机会获得CPU时间片。
Java将线程的优先级分为10个等级,分别用1-10之间的数字表示。数字越大表明线程的优先级别越高。相应地,在Thread类中定义了表线程最低最高和普通优先级的成员变量MIN_PRIORITY MAX_PRIORITY 和NORMALPRIORTTY.代表的优级等级分别为1、10和5.当一个线程对象被创建时,其默认的线程优先级是5。
1.4 守护线程
在Java中有一类被称为守护(Daemon) 线程的,比较特殊的线程,这是一种优先级比较低的线程。守护线程具有最低的优先级,一般用于为系统中的其他对象和线程提供服务。将一个线程设置为守护线程的方式是在线程对象创则之前调用线程对象的setDaemon()方法。典型的守护线程例子是Java 虚拟机中的垃圾自动回收线程,它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。可以通过调用线程对象的isDaemon()方法来判断某个线程是否是守护线程。
守护线程还有另一层含义: 当创建守护线程的父线程终止时,作为子线程的守护线程也自动终止。反之,如果一一个子线程不是守护线程,即使父线程终止了,它也不会终止。
当一个线程被创建时,它默认不是守护线程
2 Runnable接口和Thread基类
2.1实现Runnable接口
实现Runnable接口,接口只定义了一个方法,public void run()当实现该接口的对象被传递Thread类的构造方法时该对象所实现的run()方法将成为新线程的线public class MyMultiThreadClass implements Runnable
{
private int no;
public MyMultiThreadClass(int no)
{
this.no=no;
}
public void run()
{
for(int i=0;i<5;i++)
System.out.println("\t<"+i+">Hi!我是线程"+no+"!");
System.out.println("\t线程"+no+"向你说再见...");
}
}
2.2继承Thread基类
举一个实例如下:
public class MyMultiThread extends Thread
{
private int no;
public MyMultiThread(int no)
{
this.no=no;
}
public void run()
{
for(int i=0;i<5;i++)
System.out.println("\t<"+i+">Hi!我是线程"+no+"!");
System.out.println("\t线程"+no+"向你说再见...");
}
}