多线程
进程
在计算机编程中,一个基本的概念就是同时对多个任务加以控制。许多程序设计问题都要求程序能够停下手头的工作,改为处理其他一些问题,再返回主进程。可以通过多种途径达到这个目的。最开始的时候,那些掌握机器低级语言的程序员编写一些“中断服务例程”,主进程的暂停是通过硬件级的中断实现的。尽管这是一种有用的方法,但编出的程序很难移植,由此造成了另一类的代价高昂问题。中断对那些实时性很强的任务来说是很有必要的。但对于其他许多问题,只要求将问题划分进入独立运行的程序片断中,使整个程序能更迅速地响应用户的请求。
最开始,线程只是用于分配单个处理器的处理时间的一种工具。但假如操作系统本身支持多个处理器,那么每个线程都可分配给一个不同的处理器,真正进入“并行运算”状态。从程序设计语言的角度看,多线程操作最有价值的特性之一就是程序员不必关心到底使用了多少个处理器。程序在逻辑意义上被分割为数个线程;假如机器本身安装了多个处理器,那么程序会运行得更快,毋需作出任何特殊的调校。根据前面的论述,大家可能感觉线程处理非常简单。但必须注意一个问题:共享资源!如果有多个线程同时运行,而且它们试图访问相同的资源,就会遇到一个问题。举个例子来说,两个线程不能将信息同时发送给一台打印机。为解决这个问题,对那些可共享的资源来说(比如打印机),它们在使用期间必须进入锁定状态。所以一个线程可将资源锁定,在完成了它的任务后,再解开(释放)这个锁,使其他线程可以接着使用同样的资源。
多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。
最简单的比喻多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理火车也不可能只有一节车厢。多线程的出现就是为了提高效率。同时它的出现也带来了一些问题。
最开始,线程只是用于分配单个处理器的处理时间的一种工具。但假如操作系统本身支持多个处理器,那么每个线程都可分配给一个不同的处理器,真正进入“并行运算”状态。从程序设计语言的角度看,多线程操作最有价值的特性之一就是程序员不必关心到底使用了多少个处理器。程序在逻辑意义上被分割为数个线程;假如机器本身安装了多个处理器,那么程序会运行得更快,毋需作出任何特殊的调校。根据前面的论述,大家可能感觉线程处理非常简单。但必须注意一个问题:共享资源!如果有多个线程同时运行,而且它们试图访问相同的资源,就会遇到一个问题。举个例子来说,两个线程不能将信息同时发送给一台打印机。为解决这个问题,对那些可共享的资源来说(比如打印机),它们在使用期间必须进入锁定状态。所以一个线程可将资源锁定,在完成了它的任务后,再解开(释放)这个锁,使其他线程可以接着使用同样的资源。
多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。
最简单的比喻多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理火车也不可能只有一节车厢。多线程的出现就是为了提高效率。同时它的出现也带来了一些问题。
线程
每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。
线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程.
线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定. 线程的运行中需要使用计算机的内存资源和CPU。
/* 多线程: 进程:正在进行中的程序(直译),其实就是该应用程序在内存中分配的空间。 线程:是在进程中负责程序执行的一条路径。负责程序执行的。 在进程中至少有一个线程在运行。 多线程:当有多部分代码需要同时运行时,就需要开辟多条执行路径来完成。 这时该程序就是多线程程序。 多线程解决了,让多部门代码同时运行的问题。 ----------- JVM中的多线程了解。 jvm中也一样是多线程程序, 只要有一个线程负责着程序的执行。 又有一个线程负责着垃圾的回收。 这个是同时进行的。 结论: 每一个线程都有自己的运行代码,这个称之为线程的任务。 对于每一个线程便于识别都有自己的名称。 比如负责从主函数执行程序代码的线程,称之为 主线程。main thread. 主线程运行的代码都定义在主函数中。 负责收垃圾的线程:垃圾回收线程。 发现运行结果不一样。 多线程的随机性造成的,因为cpu的快速切换的原因。 final finally finalize */ class Test extends Object { /* 重写了垃圾回收器调用的方法 */ public void finalize() { System.out.println("test ok"); } } class Demoxxxx { public static void main(String[] args) { new Test(); new Test(); new Test(); new Test(); new Test(); System.gc();//调用了一次垃圾回收器。 System.out.println("Hello World!1"); System.out.println("Hello World!2"); System.out.println("Hello World!3"); System.out.println("Hello World!4"); } }
创建线程方式一
继承Thread类
子类覆盖父类中的run方法,将线程运行的代码存放在run中。
建立子类对象的同时线程也被创建。
通过调用start方法开启线程。
例程
子类覆盖父类中的run方法,将线程运行的代码存放在run中。
建立子类对象的同时线程也被创建。
通过调用start方法开启线程。
例程
/* 通过api文档发现Thread类中描述中。 有两种创建方式。 1,继承Thread类,并复写run方法。 每一个线程都应该有自己的任务,而且任务都会定义在指定的位置上。 主线程的任务都定义在main方法中。 自定义线程的任务都定义在了run方法中。 Thread t = new Thread(); t.start();//这种开启只能调用Thread类中自己的run方法。而该run方法中并未定义自定义的内容。 我还需要创建线程,还要让线程执行自定义的任务。 所以可以复写run方法。前提必须是继承Thread类。 而继承了Thread后,该子类对象就是线程对象。 */ class Demo extends Thread { private String name; Demo(String name) { this.name = name; } public void run() { for(int x=0; x<10; x++) { System.out.println("name...."+x+"....."+name); } } } class ThreadDemo { public static void main(String[] args) { //创建线程对象。 Demo d1 = new Demo("小强"); Demo d2 = new Demo("旺财"); //开启线程。让线程运行起来。 d1.start(); d2.start(); d1.run(); d2.run(); } } /* 调用run方法和调用start方法的区别? 如何定义线程名称。如果将线程名称打印在控制台上。 */
线程的四种状态
sleep方法需要指定睡眠时间,单位是毫秒。
一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。
一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。
创建线程方式二
实现Runnable接口
子类覆盖接口中的run方法。
通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
Thread类对象调用start方法开启线程。
思考:为什么要给Thread类的构造函数传递Runnable的子类对象?
子类覆盖接口中的run方法。
通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
Thread类对象调用start方法开启线程。
思考:为什么要给Thread类的构造函数传递Runnable的子类对象?
/* 创建线程的第二种方式。实现Runnable接口。 1,实现Runnable接口。 2,覆盖run方法。 3,通过Thread类创建线程对象。 4,将Runnable接口的子类对象作为实参传递给Thread类中的构造函数。 因为要让线程去运行指定的对象的run方法。 5,调用start方法开启线程,并运行Runnable接口子类的run方法。 第二种实现Runnable接口创建线程思想: 将线程任务和线程对象进行解耦,将线程任务单独封装成对象。 另,实现Runnable接口可以避免单继承的局限性。 所以建议创建多线程,都是用实现Runnable接口的方式。 */
class Ticket implements Runnable { private int num = 100; public void run() { while(true) { if(num>0) { // try{Thread.sleep(10);}catch(InterruptedException e){}//让线程在这里小睡,导致了 0 -1 等错误票的产生。 // 出现了线程安全问题。 System.out.println(Thread.currentThread().getName()+"..sale:"+num--); } } } }
如何启动线程
class ThreadDemo3_Ticket_Runnable { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }