@Yano
2017-08-07T00:32:56.000000Z
字数 5037
阅读 2202
Java
对于JDK源码分析的文章,仅仅记录我认为重要的地方。源码的细节实在太多,不可能面面俱到地写清每个逻辑。所以我的JDK源码分析,着重在JDK的体系架构层面,具体源码可以参考:http://www.cnblogs.com/skywang12345/category/455711.html。
因为 Thread 是类,一个类只能有一个父类,但是可以有多个接口。Runnable 有更好的扩展性。
Runnable 还可以用于“资源的共享”,如果多个线程是基于同一个 Runnable 对象建立的,它们会共享 Runnable 对象上的资源。
不能重复调用。不会启动新线程。
public class jdk {public static class MyThread extends Thread {public MyThread(String name) {super(name);}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " is running.");}}public static void main(String[] args) {Thread thread = new MyThread("myThread");System.out.println(Thread.currentThread().getName()+" call mythread.run()");thread.run();System.out.println(Thread.currentThread().getName()+" call mythread.start()");thread.start();}}
输出:
main call mythread.run()
main is running
main call mythread.start()
mythread is running
分析:
在main中,直接调用thread.run()时,仅仅是调用了MyThread实例的run()方法,并没有新建线程。所以run()方法中的Thread.currentThread().getName(),仍是main()!
而在调用thread.start()后,就会启动新的MyThread线程,并调用其中的run()方法,此时Thread.currentThread().getName()为新启动线程。
public synchronized void start() {// 如果线程不是"就绪状态",则抛出异常!if (threadStatus != 0)throw new IllegalThreadStateException();// 将线程添加到ThreadGroup中group.add(this);boolean started = false;try {// 通过start0()启动线程start0();// 设置started标记started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}}}
public void run() {if (target != null) {target.run();}}
答案是:依据“对象的同步锁”。
思路:考察多线程间通信。首先需要一个线程共有的变量,来标识打印的状态。在 run 方法中,首先获取一个公共的对象,相当于是把「多线程变成顺序执行」,如果获取锁后,并不是需要打印的状态,就释放锁,进入等待;其它线程会得到锁,然后判断,如果是打印状态,就打印,然后通知所有线程,并释放锁。
public class PrintABC {private static final int PRINT_A = 0;private static final int PRINT_B = 1;private static final int PRINT_C = 2;private static class MyThread extends Thread {int which; // 0:打印A;1:打印B;2:打印Cstatic volatile int state; // 线程共有,判断所有的打印状态static final Object t = new Object();public MyThread(int which) {this.which = which;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {synchronized (t) {while (state % 3 != which) {try {t.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.print(toABC(which)); // 执行到这里,表明满足条件,打印state++;t.notifyAll(); // 调用notifyAll方法}}}}public static void main(String[] args) {new MyThread(PRINT_A).start();new MyThread(PRINT_B).start();new MyThread(PRINT_C).start();}private static char toABC(int which) {return (char) ('A' + which);}}
并不会释放锁!
让当前线程休眠,由“运行状态”→“阻塞状态”。并不会释放任何锁,到时间后线程会进入“就绪状态”。
// SleepLockTest.java的源码public class SleepLockTest{private static Object obj = new Object();public static void main(String[] args){ThreadA t1 = new ThreadA("t1");ThreadA t2 = new ThreadA("t2");t1.start();t2.start();}static class ThreadA extends Thread{public ThreadA(String name){super(name);}public void run(){// 获取obj对象的同步锁synchronized (obj) {try {for(int i=0; i <10; i++){System.out.printf("%s: %d\n", this.getName(), i);// i能被4整除时,休眠100毫秒if (i%4 == 0)Thread.sleep(100);}} catch (InterruptedException e) {e.printStackTrace();}}}}}
输出的结果(t1 和 t2 的顺序不定,但是必定是同时执行0~9,因为 sleep 并没有释放锁):
t1: 0
t1: 1
t1: 2
t1: 3
t1: 4
t1: 5
t1: 6
t1: 7
t1: 8
t1: 9
t2: 0
t2: 1
t2: 2
t2: 3
t2: 4
t2: 5
t2: 6
t2: 7
t2: 8
t2: 9
让“主线程”等待“子线程”结束之后才能继续运行。
// 主线程public class Father extends Thread {public void run() {Son s = new Son();s.start();s.join();...}}// 子线程public class Son extends Thread {public void run() {...}}
在上述代码中,是 Father 线程,在 son 子线程运行结束后,再继续运行。
public final synchronized void join(long millis)throws InterruptedException {long base = System.currentTimeMillis();long now = 0;if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");}if (millis == 0) {while (isAlive()) { // isAlive() 通过子线程调用,则判断的就是子线程wait(0); // 等待的是当前线程(CPU 正则运行的线程),而不是子线程!}} else {while (isAlive()) {long delay = millis - now;if (delay <= 0) {break;}wait(delay);now = System.currentTimeMillis() - base;}}}
public class MyThread extends Thread {@Overridepublic void run() {System.out.println("MyThread start ...");for (int i = 0; i < 1000000; i++) {}System.out.println("MyThread end ...");}}@Testpublic void testJoin() throws InterruptedException {Thread thread = new MyThread();thread.start();thread.join();System.out.println("testJoin end ...");}
输出:
MyThread start ...
MyThread end ...
testJoin end ...
我们可以看到,调用了 join() 后,主线程输出的testJoin end ...是在MyThread end ...之后,这是因为main线程等待thread线程执行结束后,才继续执行。
虽然是调用子线程的wait()方法,但是它是通过“主线程”去调用的;所以,休眠的是主线程,而不是“子线程”!
wait() 源码的注释:Causes the current thread to wait
需要注意的是:Java虚拟机在“用户线程”都结束后会后退出。
答案:不是。main()方法启动的是非守护线程,如果只有这个线程,在mian()的最后一行代码,JVM 会退出(因为所有非守护进程都死了)。
验证代码:
public static void main(String[] args){System.out.println(Thread.currentThread().getName());System.out.println(Thread.currentThread().isDaemon());}
输出:
main
false
当Java虚拟机启动时,通常有一个单一的非守护线程(该线程通过是通过main()方法启动)。JVM会一直运行直到下面的任意一个条件发生,JVM就会终止运行: