1.线程的生命周期
创建线程–>调用start()就绪–>等待CPU时间片调度后运行–>死亡
2.创建线程的方法
到底有多少种呢?
a)1.继承Thread,覆盖父类的run方法
b)2.实现Runable接口,实现run方法
c)3.实现Callable接口,实现call()方法,Callable传入FutureTask对象的构造函数;
因为FutureTask是实现RunnableFuture接口,RunnableFuture 接口继承Runnable, Future两个接口,所以FutureTask可以当作Runable传入new Thread();
泛型V是返回类型,所以方法3是有返回值的线程调用
(其实callable还是属于方法2)
public class NewThread {
//方法一
public static class UserThread extends Thread{
@Override
public void run() {
System.out.println("This is UserThread -- " + Thread.currentThread().getName());
}
}
//方法二
public static class UserRunnable implements Runnable{
@Override
public void run() {
System.out.println("This is UserRunnable -- " + Thread.currentThread().getName());
}
}
public static void main(String[] args) {
UserThread userThread = new UserThread();
userThread.start();
UserRunnable userRunnable = new UserRunnable();
new Thread(userRunnable).start();
}
}
//方法3
public class UseFuture {
/*实现Callable接口,允许有返回值*/
private static class UseCallable implements Callable<Integer>{
private int sum;
@Override
public Integer call() {
System.out.println("Callable子线程开始计算!");
for(int i=0 ;i<5000;i++){
// if(Thread.currentThread().isInterrupted()) {
// System.out.println("Callable子线程计算任务中断!");
// return null;
// }
/*try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
sum=sum+i;
System.out.println("sum="+sum);
}
System.out.println("Callable子线程计算结束!结果为: "+sum);
return sum;
}
}
public static void main(String[] args) {
UseCallable useCallable = new UseCallable();
//包装
FutureTask<Integer> futureTask = new FutureTask<>(useCallable);
new Thread(futureTask).start();
Random r = new Random();
int r1 = r.nextInt(100);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("**********r1 value = "+r1);
if(r1>50){
try {
System.out.println("Get UseCallable result = "+futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}else{
System.out.println("Cancel................. ");
futureTask.cancel(true);
}
}
}
3.run()方法跟start()方法的区别,我们都知道,创建一个线程之后,线程要启动就是执行start()方法,所以,start()方法就是启动线程的方法,通过调用本地方法(native)的start0方法,启动线程,而run()方法其实就是一个普通的方法,供给线程跑业务用的;
4.join()方法的使用
可以理解成CPU资源抢夺,运行中的线程A里面,B线程调用了join()方法,则A让出时间资源,进入阻塞状态,等待B线程执行完成之后,A重新进入就绪状态进入抢占CPU时间资源列表
5.yield()方法的使用
运行中线程A调用yield()方法之后,则让出时间片,进入就绪状态重新等待CPU调度,不会释放锁资源
6.sleep()方法的使用
线程进入睡眠,等待唤醒或者设置的时间到了,线程进入睡眠不释放锁资源
7.wait()
8.notify()/notifyAll()
9.interrupte的使用
a)interrupt()方法:
用处:中断当前线程,调用之后,会使得当前线程收到一个中断请求状态,但是不会直接中断,需自行处理(协作式)
例子:
以下代码执行了interrupt()方法之后,还是会继续run()方法里面的业务代码
public class EndThread {
public static class UserThread extends Thread{
@Override
public void run() {
String threadName = Thread.currentThread().getName();
Long startTime = System.currentTimeMillis();
while (true){
//while (!Thread.interrupted()){
System.out.println("Thread is running ...and use time : " + (System.currentTimeMillis()-startTime));
}
//System.out.println(threadName + " interrupt : " + Thread.interrupted());
}
}
public static void main(String[] args) {
UserThread userThread = new UserThread();
userThread.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
userThread.interrupt();
}
}
可以把while里面的true改为!Thread.interrupted(),判断当前线程是否被中断
b)interrupted()
这是一个静态方法,用来判断当前线程是否被中断,返回boolean,调用之后,当前线程状态重置为非中断状态
c)isInterrupted()
用来判断使用的线程是否被中断,返回boolean
d)interrupted 与isInterrupted 的区别
interrupted 是一个静态的,调用之后,当前线程会被变成非中断状态,源码注释这样写的: if the current thread has been interrupted;意思是这个只能用在当前线程
isInterrupted 非静态的,调用之后线程状态不变,也可以带入参数改变线程状态,源码注释这样写的: if this thread has been interrupted;
e)死锁是不会理会中断标志的
10.线程的结束
a)Thread的stop()方法,但是一般不会建议使用这个,因为这个方法会直接将线程强制停止,导致业务执行到一半,线程占用的资源不会正常释放,容易出现问题;
一个很重要的概念,线程应该是协作式的,而不是强制式;
b)线程里面的业务代码执行完毕,正常结束
c)收到interrupt中断请求后。代码结束当前业务