线程
一、前言:
提及多线程不得不提及“进程”这个概念。“百度百科”里对“进程”的解析如下:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
初看这个文字会觉得十分的抽象,难以理解。但看到下面的图片,大家可能会对“进程”有一个感性的认知。一个PID对应一个进程。(P表示process)
linux系统中进程的表现形式如下:
那什么是线程呢?线程可以理解成是在进程中独立运行的子任务。比如QQ.exe运行时就会有很多的子任务在同时运行。比如,好友视频线程、下载文件线程、传输数据线程、发送表情线程等。这些不同的任务或者说功能都可以同时运行,其中每一个任务完全可以理解成是“线程”在工作,传文件、听音乐、发送图片表情等功能都有对应的线程在后台默默地运行。
(PS:任务是最抽象的,是一个一般性的术语,指由软件完成的一个活动。一个任务既可以是一个进程,也可以是一个线程。简而言之,它指的是一系列共同达到某一目的的操作。 )
还是来张图吧,看一看“酷我”进程对应的线程数为45个。
二、多线程优势
为了更好的理解多线程的优势,看下图单任务和多任务的模型图。
任务1和任务2是两个完全独立、互不相关的两个任务。
在单任务环境下,任务1等待远程服务器返回数据,以便进行后期的处理,这是cpu一直处于等待状态,如果任务2是10s之后被运行,虽然任务2用的时间仅有1秒,但也必须在任务1结束后才能运行任务2。单任务的特点就是排队执行,也就是同步,就像在cmd中输入一条命令后,必须等待这条命令执行完才可以执行下一条命令一样。这就是单任务环境的缺点,即CPU利用率非常低。
在多任务环境下,CPU完全可以在任务1和任务2之间来回切换,使任务2不必等到10s再运行。CPU的利用率大大提高。这就是要使用多线程技术、要学习多线程的原因。这是多线程的优点,使用多线程也就是在使用异步。
三、使用多线程
一个进程正在运行时至少会有1个线程在运行,这种情况在java中是存在的。这些线程在后台默默地执行,比如调用public static void main()方法的线程就是这样的,而且它是由JVM创建的。如下图
在控制台中输出的main其实就是一个名词叫做main的线程在执行main方法中的代码。另外需要说明一下,在控制台输出的main和main方法没有任何的关系。仅仅是名字一样。
1、线程调用的随机性:
线程调用具有随机性,也就是说代码的运行结果与代码执行顺序或调用顺序是无关的。
2、线程的随机性
public class ThreadTest1 extends Thread {
//测试线程的随机数
public void run(){
try {
for (int i = 0; i < 10; i++) {
int time=(int)(Math.random()*1000);
Thread.sleep(time);
System.out.println("正在运行的线程名为:" +Thread.currentThread().getName());
}
} catch (Exception e) {
e.printstacktrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
ThreadTest1 threadTest1=new ThreadTest1();
threadTest1.setName("ThreadTest1");
threadTest1.start();
for (int i = 0; i < 10; i++) {
int time=(int)(Math.random()*1000);
Thread.sleep(time);
System.out.println("正在运行的线程名为:" +Thread.currentThread().getName());
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
输出结果为:
为了展示线程具有随机特性,所以使用随机数的形式来模拟线程挂起的效果。从而表现出CPU执行哪个线程具有不确定性。
Thread类中的start()和run()方法有什么区别?
线程通常都有5种状态:创建、就绪、运行、阻塞和死亡。
1)、创建状态:在生成线程对象,没有调用该对象的start()方法之前,这时线程处于创建状态。
2)、就绪状态:当调用了线程对象的start方法之后,该线程就进入就绪状态,但此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或睡眠中回来之后,也会处于就绪状态。
3)、运行状态:线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入运行状态,开始运行run函数当中的代码。
4)、阻塞状态:线程正在运行的时候,被暂停之后再继续运行。sleep、suspend、wait等方法都可以导致线程阻塞。
5)、死亡状态:如果一个线程的run方法 执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。
(Thread的run和start的区别、Java线程的5种状态及转换)
举个栗子:下列代码的输出结果是 :
当调用start方法时,为②。只有调用start才是开启线程。
当调用run方法时,为①。
① 一定是先“run” 后 “main”
② “run”和“main”的顺序不固定:有时先run后main,有时先main后run。
public static void main(String[] args) {
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("run");
}
};
Thread thread=new Thread(runnable);
//thread.run();
thread.start();
System.out.println("main");
}
相关阅读
http://blog.csdn.net/jiazhen/article/details/1611721简介线程之间通信的两个基本问题是互斥和同步。线程同步是指线程之间所具
怎么样才算得上熟悉多线程编程?第一,明白进程和线程的基本概念第二,明白保护线程安全的基本方法有哪些第三,明白这些线程安全的方法,包
KILL MYSQL SQL出现线程无法终止,出现freeing items现
KILL查询SQL出现线程无法终止,出现freeing items现象问题; 实例:今天公司DB 有大量的线程是freeing items 状态。DB服务器上跑应用,还
SessionFactory有什么作用? SessionFactory线程安全吗
这也是Hibernate框架的常见面试问题。顾名思义,SessionFactory就是一个用于创建Hibernate的Session对象的工厂。SessionFactory通
线程池原理(四):ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor用于定时任务,这里的定时意义在于: 指定延时后执行任务。 周期性重复执行任务。 我们接着分析Sched