1.Thread类详解:
无论是通过继承Thread还是实现Runnable接口来实现多线程编程,都离不开Thread。
Thread译为线程,线程有以下几种状态,接下来我会按照Thread类中的方法来逐一讲解。
1.Thread t = new Thread()仅仅只是创建了线程,并没有为线程分配任何资源
2.start()方法用来启动线程,为相应地线程分配资源,分配到资源才能参与到竞争CPU的过程中
run():当start()启动一个线程后,线程一直等待直到获得了CPU执行时间,就进入run方法体
3.sleep()让线程休眠,主动让出CPU,但是不会释放锁,休眠时间满后,不一定立即得到执行,还需要重新参与竞争排队
public class MyThread{
private int i = 10;
public Object lock = new Object();
public static void main(String[] args) {
MyThread mh = new MyThread();
ThreadTest tt = mh.new ThreadTest();
ThreadTest tt2 = mh.new ThreadTest();
tt.start();
tt2.start();
}
class ThreadTest extends Thread{
@Override
public void run() {
synchronized (lock) {
i++;
System.out.println("i:" + i);
try {
System.out.println(Thread.currentThread().getId()+"睡眠开始");
Thread.currentThread().sleep(1000);//睡眠并不释放锁
} catch (Exception e) {
}finally {
System.out.println(Thread.currentThread().getId()+"睡眠结束");
}
i++;
System.out.println("i:" + i);
}
}
}
}
输出:
i:11
10睡眠开始
10睡眠结束
i:12
i:13
11睡眠开始
11睡眠结束
i:14
4.yield()使线程让出CPU去执行相同优先级的其他程序,但是不会释放锁,(内部还是sleep)执行yield()之后该线程直接再次参与竞争,而不进行阻塞等待。
5.A线程的run()中调用了B线程的join(),则A线程等待B线程执行完之后,再继续执行,实际上调用了Object类中的wait()方法,会释放锁
/**
* Created by liuyl on 15/11/27.
* 调用了thread.join需要等到thread的run方法执行完毕,主线程才可以继续执行
*/
public class ThreadJoin {
public static void main(String[] args) throws IOException {
System.out.println("进入线程"+Thread.currentThread().getName());
ThreadJoin test = new ThreadJoin();
MyThread thread1 = test.new MyThread();
thread1.start();
try {
System.out.println("线程"+Thread.currentThread().getName()+"等待");
thread1.join();
System.out.println("线程"+Thread.currentThread().getName()+"继续执行");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class MyThread extends Thread{
@Override
public void run() {
System.out.println("进入线程"+Thread.currentThread().getName());
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("线程"+Thread.currentThread().getName()+"执行完毕");
}
}
}
输出结果:
进入线程main
线程main等待
进入线程Thread-0
线程Thread-0执行完毕
线程main继续执行
join中调用了wait()方法:thread1.join()调用了wait方法
其中wait()在Jdk中的源码为:
public final native void wait(long timeout) throws InterruptedException;
wait为native方法
6.interrupt()使得处于阻塞状态的线程抛出一个异常,也就是说,它可以中断并且只能中断一个处于阻塞状态的线程
public class MyThread{
public static void main(String[] args) {
MyThread mh = new MyThread();
ThreadTest tt = mh.new ThreadTest();
tt.start();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tt.interrupt();
}
class ThreadTest extends Thread{
@Override
public void run() {
try {
System.out.println("子线程睡眠开始");
Thread.currentThread().sleep(10000);
System.out.println("子线程睡眠结束");
} catch (InterruptedException e) {
System.out.println("子线程获取到中断");
}
System.out.println("run执行完毕");
}
}
}
输出结果:
子线程睡眠开始
子线程获取到中断
run执行完毕
7.开发中一般不使用interrupt()而在类中增加isStop属性来标志是否结束while循环
class MyThread extends Thread{
private volatile boolean isStop = false;
@Override
public void run() {
int i = 0;
while(!isStop){
i++;
}
}
public void setStop(boolean stop){
this.isStop = stop;
}
}
那么就可以在外面通过调用setStop方法来终止while循环。
2.上下文切换:
对于两个线程来说,如果是单核CPU的计算机,一个时刻只能运行一个线程,线程切换指的是线程A中断释放出CPU转让CPU资源给线程B运行。
对于线程切换,需要保存线程的上下文,以方便线程B执行完释放CPU给线程A时,线程A能继续从刚才保存的断点执行。
所以CPU需要记录,线程执行到哪里(程序计数器),线程挂起时的变量(CPU寄存器状态)等