线程 Thread.class

1. 线程的六种状态

- NEW
 尚未启动的线程处于此状态。
- RUNNABLE
 在Java虚拟机中执行的线程处于此状态。
- BLOCKED
 被阻塞等待监视器锁定的线程处于此状态。
- WAITING
 正在等待另一个线程执行特定动作的线程处于此状态。
- TIMED_WAITING
 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
- TERMINATED
 已退出的线程处于此状态。
Thread.State getState()	// 返回此线程的状态。  

2. 线程的常用方法
long getId()					// 返回此线程的标识符。
static Thread currentThread()	// 返回对当前正在执行的线程对象的引用。String getName()	// 返回此线程的名称。
void setName(String name)	// 将此线程的名称更改为等于参数 name 。void setPriority(int newPriority)	// 更改此线程的优先级。
int getPriority()	// 返回此线程的优先级。boolean	isAlive()			// 测试这个线程是否活着。
boolean	isInterrupted()	    // 测试当前线程是否中断。void start()	 // 导致此线程开始执行; Java虚拟机调用此线程的run方法。
void interrupt() // 中断这个线程。void join()	 // 等待这个线程死亡(用来控制线程结束的顺序,让调用这个方法的线程先执行完)
// 调用该方法的线程将会一直占用处理机,把其它线程都阻塞,直至该线程结束,再执行其它线程
// 同样使用join()也会产生异常InterruptExceptionstatic void	sleep(long millis) // 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)
// sleep执行后会产生异常InterruptedException,需要捕捉或抛出
// 每个对象都有一把锁,sleep不会释放这把锁static void	yield()	// 对调度程序的一个暗示,即当前线程愿意产生当前使用的处理器。
// 礼让线程,让当前正在执行的线程暂停,从运行状态转换为就绪状态
// 礼让不一定成功,可能CPU依旧重新调度该线程
public Thread()					// 分配一个新的Thread对象。
public Thread(String name)		// 创建一个新的Thread对象,并指定线程名称
public Thread(Runnable target)	// 封装Runnable对象为线程对象
public Thread(Runnable target, String name)	// 封装Runnable对象为线程对象,并指定线程名称
3. 线程的创建
3.1. 继承Thread类
继承Thread类,重写run()方法,调用start()启动线程
public class TestThread extends Thread {@Overridepublic void run() {// 线程运行逻辑}
}public class Main {public static void main(String [] args) {TestThread testThread = new TetsThread();testThread.strat();}
}3.2. 实现Runnable接口
继承Thread类,重写run()方法,调用start()启动线程
public class TestThread implements Runnabel {@Overridepublic void run() {// 线程运行逻辑}
}public class Main {public static void main(String [] args) {TestThread testThread = new TetsThread();// Thread thread = new Thread(testThread);// thread.start();// 更简便的写法new Thread(testThread).start();}
}
- 继续Thread类虽然启动线程的方式更简单,但是具有单继承局限性;
- 实现Runnable接口,启动线程需要使用new一个Thread类来启动,但是可以避免单继承局限性(用于实现一份资源,多个代理)
public class TestThread implements Runnable {// 票数private int ticketNums = 10;// 模拟抢票@Overridepublic void run() {while (true) {if (ticketNums <= 0) {break;}System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNums-- +"票" );}}public static void main(String[] args) {TsetThread ticket = new TestThread();// 虽然有多个对象,但是都共用一份资源new Thread(ticket, "a").start();new Thread(ticket, "b").start();new Thread(ticket, "c").start();}
}
3.3. 实现Callable接口
实现Callable接口,定义接口返回值类型,重写call方法并抛出异常
 相比Runnable接口,Callable接口允许线程执行任务并返回结果,它的call()方法还可以自定义抛出异常。
public class TestCallable implements Callable<Boolean> {// 定义成员变量// 定义构造器@Overridepublic Boolean call() throws Exception {// 编写线程需要执行的任务return true;}public static void main(String[] args) throws Exception {// 创建线程池ExecutorService ser = Executors.newFixedThreadPool(1);// 提交Callable任务,并获取Future对象Future<Boolean> future = executor.submit(new TestCallable());// 获取线程执行结果Boolean result = future.get();System.out.println(result);// 关闭线程池executor.shutdown();}
}
Callable创建线程的底层原理
- 当通过**ExecutorService**的**submit()**方法提交**Callable**任务时,线程池会将**Callable**任务封装成一个**FutureTask**对象。
- **FutureTask**对象实现了- **RunnableFuture**接口,而- **RunnableFuture**接口继承自- **Runnable**接口,因此- **FutureTask**对象也可以作为- **Runnable**任务被线程执行。
- 线程池会选择一个空闲的线程执行**FutureTask**对象中的**run()**方法,而**run()**方法实际上会调用**Callable**对象的**call()**方法执行任务。
- 当任务执行完成后,**FutureTask**对象会保存任务的执行结果,其他线程可以通过**Future**对象的**get()**方法获取执行结果。
注意:
- 多线程中,主线程调用完start()之后,会继续执行自己路线,并不用等子线程执行完了再继续执行下去;

- 线程启动之后,并不一定立即执行,只是进入了线程就绪状态,具体运行时间由CPU调度安排(也就是说在多线程环境下,即使多个线程依次start但真实执行顺序却不一定按序);
补充:
 函数式接口:
- 接口中只包含唯一一个抽象方法,就称为函数式接口,例如Runnable接口就是一个函数式接口;对于函数式接口可以直接用lambda表达式直接创建该接口的对象;
- 编写函数式强制接口里面只能有一个抽象方法,使用时需带有这个注释@FunctionalInterface,该注解可用于一个接口的定义上。一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错.
@FunctionalInterface
public interface Runnable {/*** When an object implementing interface <code>Runnable</code> is used* to create a thread, starting the thread causes the object's* <code>run</code> method to be called in that separately executing* thread.* <p>* The general contract of the method <code>run</code> is that it may* take any action whatsoever.** @see     java.lang.Thread#run()*/public abstract void run();
}package text1;public class TestLambda {// 3. 静态内部类static class Like2 implements ILike {@Overridepublic void lambda() {System.out.println("静态内部类接口实例化");}}public static void main(String[] args) {ILike like = new Like();like.lambda();like = new Like2();like.lambda();// 4. 局部内部类class Like3 implements ILike {@Overridepublic void lambda() {System.out.println("局部内部类接口实例化");}}like = new Like3();like.lambda();// 5. 匿名内部类like = new ILike() {@Overridepublic void lambda() {System.out.println("匿名内部类接口实例化");}};like.lambda();// 6. lambda表达式简化匿名内部类like = () -> {System.out.println("匿名内部类接口实例化");};like.lambda();// 7. lambda表达式简化like = () -> System.out.println("lambda表达式简写");like.lambda();}}// 1. 定义一个函数式接口
interface ILike {void lambda();
}// 2. 实现类
class Like implements ILike {@Overridepublic void lambda() {System.out.println("1");}
}
Lambda表达式
- 用于简化函数式接口的实例对象,本质其实是一个接口的实例对象;
- 语法:
Lambda表达式的标准格式为:(参数类型 参数名称) ‐> { 代码语句 }
- 小括号里面放参数列表
- 箭头用来连接参数列表和方法体
- 箭头后面的大括号内放方法体
- 语法省略规则: - 参数列表中的所有参数类型都可以省略,但需要同时省略;若只有一个参数,小括号都可以同时省略,如(String s)简写成s
- 如果方法体里只有一行代码,就可以直接省略大括号{}和语句结尾的分号;
 
- 参数列表中的所有参数类型都可以省略,但需要同时省略;若只有一个参数,小括号都可以同时省略,如
如:hh( (String s)-> {System.out.println(s) } ),因为在hh这个方法的参数列表中提前指明了接口类型 , 所以写成Lambda形式,是能被系统自动识别出是对谁的简写。
4. 线程的关闭
线程关闭可以使用设置标志位flag的方法,设定当线程方法体中达成了某种变化使得标志位改变,从而使线程停止;
 不推荐使用JDK已废弃的stop()方法和destroy()方法
@Override
public void run() {while (flag) {// 线程执行内容}
}