线程就是程序中单独顺序的流控制。java
线程自己不能运行,它只能用于程序中。编程
说明:线程是程序内的顺序控制流,只能使用分配给程序的资源和环境。安全
进程:操做系统中执行的程序多线程
程序是静态的概念,进程是动态的概念。ide
一个进程能够包含一个或多个线程。spa
一个进程至少要包含一个线程。操作系统
单个程序中只有一个执行路径就是单线程。 线程
当程序启动运行时,就自动产生一个线程,主方法main就在这个主线程上运行。咱们的程序都是由线程来执行的。code
多线程指在单个程序中能够同时运行多个不一样的线程执行不一样的任务。对象
多线程编程的目的,就是“最大限度地利用CPU资源”,当某一线程的处理不须要占用CPU而只和IO等资源打交道时,让须要占用CPU的其余线程有机会得到CPU资源。从根本上说,这就是多线程编程的最终目的。
一个程序实现多个代码同时交替运行就须要产生多个线程。
CPU随机地抽出时间,让咱们的程序一会作这件事情,一会作另外的事情。
从宏观角度来看,多个线程在同时执行(宏观并行),可是微观上来看,处理器的个数决定了某一个时刻能够同时运行的最大线程数,
如单核CPU某一时刻只能有一个线程在执行(微观串行),双核的CPU在某一个时刻,最多能够运行两个线程,能够作到微观并行。
1.继承Thread类并重写它的run方法。以后建立这个子类的对象并调用start()方法。
2.经过定义实现Runnable接口的类进而实现run方法。这个类的对象在建立Thread的时候做为参数被传入,而后调用start()方法。
Thread类是专门用来建立线程和对线程进行操做的类。当某个类继承了Thread类以后,该类就叫作一个线程类。
两种方法均需执行线程的start()方法为线程分配必须的系统资源、调度线程运行并执行线程的run()方法。
注意:start()方法是启动线程的惟一的方法。start()方法首先为线程的执行准备好系统资源,而后再去调用run()方法。
run()方法中放入了线程的工做,即咱们要这个线程去作的全部事情。缺省情况下run()方法什么也不作。
1.经过继承Thread类实现多线程
/** * 经过Thread实现线程 */ Thread thread1 = new Thread() { @Override public void run() { while (true) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("thread1:" + Thread.currentThread().getName()); } } }; thread1.start();
2.经过实现runnable接口实现多线程
/** * 经过Runnable接口实现线程 */ Thread thread2 = new Thread(new Runnable() { public void run() { while (true) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("thread2:" + Thread.currentThread().getName()); } } }); thread2.start();
Thread类也实现了Runnable接口,所以实现了接口中的run()方法。
当生成一个线程对象时,若是没有为其指定名字,那么线程对象的名字将使用以下形式:Thread-number,该number是自动增长的数字,并被全部的Thread对象所共享,由于它是一个static的成员变量。
当使用第一种方式(继承Thread的方式)来生成线程对象时,咱们须要重写run()方法,由于Thread类的run()方法此时什么事情也不作。
当使用第二种方式(实现Runnable接口的方式)来生成线程对象时,咱们须要实现Runnable接口的run()方法
线程的消亡不能经过调用stop()命令,而是让run()方法天然结束。stop()方法是不安全的,已经废弃。
中止线程推荐的方式:设定一个标志变量,在run()方法中是一个循环,由该标志变量控制循环是继续执行仍是跳出;循环跳出,则线程结束。
1.建立状态:
当用new操做符建立一个新的线程对象时,该线程处于建立状态。
处于建立状态的线程只是一个空的线程对象,系统不为它分配资源。
2.可运行状态:
执行线程的start()方法将为线程分配必须的系统资源,安排其运行,并调用线程体——run()方法,这样就使得该线程处于可运行状态(Runnable)。
这一状态并非运行中状态(Running),由于线程也许实际上并未真正运行。
3.不可运行状态:
当发生下列事件时,处于运行状态的线程会转入到不可运行状态:
调用了sleep()方法;
线程调用wait()方法等待特定条件的知足;
线程输入/输出阻塞。
返回可运行状态:
处于睡眠状态的线程在指定的时间过去后;
若是线程在等待某一条件,另外一个对象必须经过notify()或notifyAll()方法通知等待线程条件的改变;
若是线程是由于输入输出阻塞,等待输入输出完成。
sleep与wait区别:
1.对于sleep()方法,咱们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
2.sleep()方法致使了程序暂停执行指定的时间,让出cpu该其余线程,可是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
在调用sleep()方法的过程当中,线程不会释放对象锁。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备
notify与notifyall区别
notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。 void notify(): 唤醒一个正在等待该对象的线程。 void notifyAll(): 唤醒全部正在等待该对象的线程。 二者的最大区别在于: notifyAll使全部原来在该对象上等待被notify的线程通通退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。 notify他只是选择一个wait状态线程进行通知,并使它得到该对象上的锁,但不惊动其余一样在等待被该对象notify的线程们,
当第一个线程运行完毕之后释放对象上的锁,此时若是该对象没有再次使用notify语句,即使该对象已经空闲,其余wait状态等待的线程因为没有获得该对象的通知,
继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。
4.消亡状态:
当线程的run()方法执行结束后,该线程天然消亡。
1.线程的优先级及设置
线程的优先级是为了在多线程环境中便于系统对线程的调度,优先级高的线程将优先执行。
一个线程的优先级设置听从如下原则:
线程建立时,子继承父的优先级。
线程建立后,可经过调用setPriority()方法改变优先级。
线程的优先级是1-10之间的正整数。
1- MIN_PRIORITY
10-MAX_PRIORITY
5-NORM_PRIORITY
若是什么都没有设置,默认值是5。
可是不能依靠线程的优先级来决定线程的执行顺序。
2.线程的调度策略
线程调度器选择优先级最高的线程运行。可是,若是发生如下状况,就会终止线程的运行:
线程体中调用了yield()方法,让出了对CPU的占用权。
线程体中调用了sleep()方法,使线程进入睡眠状态。
线程因为I/O操做而受阻塞。
另外一个更高优先级的线程出现。
在支持时间片的系统中,该线程的时间片用完。