一、三个基本概念:程序、进程、线程
程序:是为了完成特定的任务、用某种语言所编写的一组语言的集合。即指一段静态的代码。
进程:是程序的一次执行过程,或是正在运行的程序。是一个动态的过程:有它自身的产生、存在和消亡过程。
>进程作为资源分配的单位,系统在巡行时会为每个进程分配不同的内存区域。
线程:进程可以进一步细化为线程,是一个程序内部的一条执行路径。
>若一个进程同一时间并行的执行多个线程,就是支持多线程。
>线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc)。线程的切换开销小。
>一个进程的多个线程可以共享资源,这使得线程间的通讯更加便捷高效,但是同样的带来了安全隐患。
二、单核CPU和多核CPU的理解:
单核CPU:其实是一种假的多线程,因为在一个时间单元内,只能执行一个线程的任务。但是由于CPU时间单元特别短,感觉就好像是同时在做一样。
多核CPU:多核才是正在的多线程,能更好的发挥多线程的效率,一个java应用程序java.exe其实至少有三个线程:main()主线程、gc()垃圾回收线程、异常处理线程。异常发生,会影响主线程。
三、并发和并行:
并行:多个CPU同时执行多个任务。多个人做不同事。
并发:一个CPU同时执行多个任务。比如:秒杀、多个人做一件事。
四、多线程的创建:
方式一:继承于Thread类
1.创建一个继承于Thread类的子类
2.重写Thread类的run()——>将此线程执行的操作放到run()中
3.创建Thread类的子类的对象
4.通过此对象调用start()
例如:遍历100以内的所有偶数:
class example extends Thread{ @override public void run(){ for(int i = 0;i<100;i++){ if(i %2 == 0){ System.out.print(i); }}}} public class exampletest{ public static void main(String【】args){ example ex = new example();//每创建一个对象,就可以创建一个线程的调用 ex.start();//启动当前线程,调用当前线程的run()方法 System.out.print("hello"); } }
这个时候main线程下的打印“hello”和start方法的遍历就是分开进行的。
方式二:实现Runnable接口
1.创建一个实现了Runnable接口的类
2.实现类去实现Runnable中的抽象方法:run()
3.创建实现类的对象
4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start()
class example implements Runnable{ @override public void run(){ for(int i = 0;i<100;i++){ if(i %2 == 0){ System.out.print(i); }}}} public class exampletest1{ public static void main(String【】args){ example ex = new example();//创建实现类的对象 Thread th = new Thread(ex);//将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象 th.start();//启动当前线程,调用当前线程的run()方法(通过查看源码,其实这个run()调用的是Runnable类型的target,而这个就是作为实参传递的实现类对象!) System.out.print("hello"); }
比较以上两种创建线程的方式:
开发中:优先选择实现Runnable接口的方式
原因:1.实现的方式没有类的单继承性的局限性
2.实现的方式更适合来处理多个线程有共享数据的情况。
联系:public class Thread implements Runnable(其实都是Runnable中的run())
相同点:两种方式都要重写run(),将线程要执行的逻辑声明在run()中。
五、Thread类的有关方法:
void start:启动线程,并执行对象的run()方法
run():线程在被调用时执行的操作
String getName():返回线程的名称
void steName(String name):设置该线程名称
static Thread currentThread():返回当前线程。在Thread子类中就是this,通常用于主线程和Runnable实现类。
static void yield():线程让步
>暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程(注意:暂停执行的线程,在抢占的时候仍然有机会抢到资源执行)
>若队列中没有同优先级的线程,忽略此方法。
join():当某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到join()方法加入的join线程执行完为止。
>低优先级的线程也可以获得执行
static void sleep(long millis):(时间单位:毫秒)
>令当前活动线程在指定时间段内放弃对CPU的控制,使其他线程有机会被执行,时间到后重新排队。
>抛出InterruptedException异常。
stop():强制线程生命期结束,不推荐使用(过时了)
boolean isAlive():判断线程是否还活着。
六、线程的调度:
java的调度方法:
>同优先级线程组成先进先出(先到先服务),使用时间片策略
>对高优先级,使用优先调度的抢占式策略
线程的优先级等级:
>MAX_PRIORITY: 10
>MIN_PRIORITY: 1
>NORM_PRIORITY: 5
涉及的方法:
>getPriority():返回线程优先值
>setPriority(int newPriority):改变线程的优先级
说明:
>线程创建时继承父线程的优先级
>低优先级只是获得调用的概率低,并非一定是在高优先级线程之后才被调用