并发编程是对计算机性能压榨的最好的方法。

一、概述

Java程序是通过线程执行的,线程在程序中具有独立的执行路径。当多条线程执行时,他们彼此之间的路径可以不同。举个例子,一条线程可能在执行switch语句的某个case分支,另一条线程可能在执行其它case分支。

 每个java应用程序都有一个执行main()函数的默认主线程。应用程序也可以创建线程在后台操作时间密集型任务,以确保堆用户的响应。这些封装了代码执行序列的线程对象就被称为Runnable

Java虚拟机给每条线程分配独立的JVM栈空间以免彼此干扰。独立的栈使得线程可以追踪他们自己下一条要执行的指令(指令计数器),这些指令会依线程不同而有所区别。栈空间也为每条线程单独准备了一份方法参数、局部变量以及返回值的拷贝

Java主要是通过java.lang.Thread类以及java.lang.Runnable接口实现线程机制的。

单个的操作系统线程和一个Thread对象关联,至于使用什么样的线程模型可以通过jvm指定,目前有两种线程模型

一种是内核线程管理用户线程的模型,另一种是内核线程管理进程,进程负责管理由它创建的线程。两者各有好处,不过主流使用第二种模型,内核-进程-线程,因为线程的运行需要申请和占用cpu的使用权,而cpu何时给予线程使用权和何时剥脱它的使用权时不确定的。所以就会产生一系列线程阻塞、死锁等问题,就需要使用者添加各种机制确保线程同步从而完成使用者的目的。

二、Thread类和Runnable接口

这个大概懂什么意思就行了,一个类想要成为线程运行只有两种方法

一是继承Thread类 extends Thread;二是实现Runnable接口 implements Runnable,然后new Thread(r).start()就可以运行了。

现在一般都是实现Runnable接口,是因为继承只能单继承,继承了Thread就继承不了别的了。而接口可以实现多个。

再者,因为线程的创建和销毁会使用大量的性能资源,所以现在都是使用线程池去使用线程的。(线程池后续再讲)

所以这部分我们只需了解Thread类和Runnable接口两种方法的实现区别和Thread的状态即可。

因为一个Thread对象关联和一条线程的状态。这个状态由线程名称、线程存活的标识、线程的执行状态、线程的优先级以及线程是否为守护线程等标识构成。

1、获取和设置线程的名称

Thread t1=new Thread(r,"thread t1"),其中r为Runnable类型

System.out.println(t1.getName());//"thread t1"

t1.setNmae("t2");

System.out.println(t1.getName());//"thread t2"

如果不设置的话,就会默认给一个Thread-作为前缀

2、获取一条线程的存活状态

Thread t=new Thread(r)//

t.isAlive();//false

一条线程的寿命仅仅起始于它真正在start()方法中被启动出来,而结束与它刚刚离开的run()方法。

当线程开始start()方法

一般情况下,线程有创建、就绪、运行、阻塞、结束五个状态,当引入挂起这个概念的时候另说,挂起是该线程放弃cpu的使用权,等待需要这个线程的时候由用户去唤醒它,当唤醒该线程后,线程会进入就绪状态,申请使用cpu。

线程创建,变成就绪状态同时申请cpu,获取到cpu了就变成运行状态了,中间如果碰到获取不到某个资源等待可能会阻塞,变为阻塞状态,正常完成Run方法后就会变成结束状态,由cpu销毁这个线程。

3、获取和设置线程的优先级

这个不是重点,因为Thread类对应的是操作系统的线程,不同的操作系统可能会对线程优先级有不同的划分,并不一定可以和jvm规划的10个等级相对应。所以这部分了解便好,让一个线程优先使用一般都是用别的方法去限制。

优先级这方面 主线程级别是5,主线程就是Main方法

你也可以给线程设置最小、最大优先级。setPriority(Thread.MIN_PRIORITY);

4、获取和设置线程的守护线程状态

java将线程分为守护和非守护线程。一条守护线程扮演非守护线程辅助者的角色,并且会在应用程序最后一条非守护线程消失之后自动死亡,因此应用程序才会终止。

默认情况下,Thread对象关联的线程都是非守护线程。

除非调用Thread 的void setDaemon(boolean isDaemon)方法

5、join方法

join方法就是把cpu资源堆到调用该方法的线程去,意思就是 其他线程运行的好好的,你一个t.join()加入到运行队列前端去,别线程都不干活了,就等你这个t完成了其他线程才干活。join方法实现的就是抢占性调度,我抢,我占,我紧急。

6、Sleep方法

让线程睡眠,但并不是完全放弃cpu使用权,cpu会监视它,直到它睡醒了,然后完成该线程接下来的任务

实现方法是,在你想睡眠的线程里的Run方法里写 Thread.sleep(1000);//单位是毫秒

7、wait和notify

着两个方法已经不被建议使用了,每个Object对象都会有wait和notify方法,wait就是把它扔到jvm的常量池里去,不再使用,直到notify()唤醒它才会使用,使用notify()时一般使用的是notifyAll()。因为你也不知道唤醒的是哪个线程。