创建线程的三种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | public class ThreadDemo extends Thread { 	 	// 1. 新建一个类继承 Thread 类,并重写 Thread 类的 run() 方法。 	@Override 	public void run() { 		System.out.println("Hello Thread"); 	} 	 	public static void main(String[] args) { 		 		// 2. 创建 Thread 子类的实例。 		ThreadDemo threadDemo = new ThreadDemo(); 		// 3. 调用该子类实例的 start() 方法启动该线程。 		threadDemo.start(); 	} }
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | public class RunnableDemo implements Runnable {
  	// 1. 创建一个类实现 Runnable 接口,并重写该接口的 run() 方法。 	@Override 	public void run() { 		System.out.println("Hello Runnable"); 	}
  	 	public static void main(String[] args) { 		 		// 2. 创建该实现类的实例。 		RunnableDemo runnableDemo = new RunnableDemo(); 		 		// 3. 将该实例传入 Thread(Runnable r) 构造方法中创建 Thread 实例。 		Thread thread = new Thread(runnableDemo); 		 		// 4. 调用该 Thread 线程对象的 start() 方法。 		thread.start(); 		 	} }
  | 
 
该方式可以获取线程执行的结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   | public class CallableDemo implements Callable<String> {
  	// 1. 创建一个类实现 Callable 接口,并重写 call() 方法。 	@Override 	public String call() throws Exception { 		System.out.println("CallableDemo is Running"); 		return "Hello Callable"; 	} 	 	public static void main(String[] args) { 		 		// 2. 创建该 Callable 接口实现类的实例。 		CallableDemo callableDemo = new CallableDemo(); 		 		// 3. 将 Callable 的实现类实例传入 FutureTask(Callable<V> callable) 构造方法中创建 FutureTask 实例。 		FutureTask<String> futureTask = new FutureTask<>(callableDemo); 		 		// 4. 将 FutureTask 实例传入 Thread(Runnable r) 构造方法中创建 Thread 实例。 		Thread thread = new Thread(futureTask); 		 		// 5. 调用该 Thread 线程对象的 start() 方法。 		thread.start(); 		 		// 6. 调用 FutureTask 实例对象的 get() 方法获取返回值。 		// 该方法阻塞直到子线程结束返回结果 		try { 			System.out.println(futureTask.get()); 		} catch (Exception e) { 			e.printStackTrace(); 		} 	} }
  | 
 
线程的三种状态
- 就绪状态:调用线程的start()方法后,处于就绪状态,随时等待cpu调度执行
 
- 运行状态:cpu调度执行run方法
 
- 阻塞状态:执行的cpu时间片到了,线程被cpu调度暂时挂起,调度其他线程执行
 
线程优先级
1 2 3 4 5 6 7 8 9
   | //设置优先级 public final void setPriority(int newPriority) //获取优先级 public final int getPriority()
  //Thread类的三个静态变量 MAX_PRIORITY:优先级为 10 NORM_PRIORITY:优先级为 5 MIN_PRIORITY:优先级为 1
   | 
 
线程优先级为1-10范围内
后台线程/守护线程
1 2 3 4
   | //将线程设置为后台线程,参数true public final void setDaemon(boolean on) //返回此线程是否为后台线程 public final boolean isDaemon()
   | 
 
后台线程的特点就是当前台线程全部结束后,后台线程就会随之结束。 
它的唯一用途就是为其他线程提供服务,如:计时器线程,定时的向其他线程发送信号或清空过时的高速缓存项线程。当程序只剩下守护线程时,JVM就退出了,因为只剩它守护线程了,没有服务对象了,也就没有再继续运行的必要了。
守护线程不应该去访问固定资源,如:文件,数据库,因为它不定在什么时候被中断,而导致资源未关闭。
native方法
native关键字说明它修饰的是一个原生态方法,它的实现不是在当前文件,而是采用其他语言编写的(如C, C++等)。
Java语言本身不能对操作系统底层方法进行访问和调用,而C,C++等语言可以,因为操作系统是采用这些语言实现的。但Java可以通过JNI接口调用其他语言来实现对底层进行访问。
Thread.currentThread()
Thread.State getState()
- 得到实例线程的当前状态,Thread.State枚举值参考JDK API
 
Thread.sleep()
1 2 3
   | //Java原生方法,实现采用其他语言实现 public static native void sleep(long millis) public static void sleep(long millis, int nanos)
   | 
 
注意为静态方法,让当前线程从运行状态到阻塞状态,参数为阻塞的时间,millis为毫秒,nanos为纳秒
yield()
1 2
   | //Java原生方法,实现采用其他语言实现 public static native void yield();
   | 
 
理论上,yield意味着放手,放弃,投降。
一个调用yield()方法的线程告诉JVM它乐意让其他同优先级线程或比它优先级高的线程占用自己的位置。即让当前线程从运行状态到就绪状态,而不是阻塞状态,稍后可能会继续被调度执行。
这表明该线程没有在做一些紧急的事情。注意,这仅是一个暗示,不能保证使得当前正在运行的线程迅速转换到可运行的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | public class YieldDemo extends Thread {
  	@Override 	public void run() {
  		for (int i = 0; i < 50; i++) { 			System.out.println(getName() + " " + i);
              //i=20时,当前线程主动让出cpu执行权, 			if (i == 20) { 				Thread.yield(); 			} 		} 	}
  	public static void main(String[] args) {
  		YieldDemo yieldDemo1 = new YieldDemo(); 		YieldDemo yieldDemo2 = new YieldDemo();
  		yieldDemo1.start();  		yieldDemo2.start(); 	} }
  | 
 
join()
1 2 3
   | public final void join() throws InterruptedException public final synchronized void join(long millis) throws InterruptedException
 
   | 
 
这个方法要有两个线程,也就是一个线程t1的线程体中有另一个线程t2调用join()方法,即t1的run方法中有t2.join()调用,此时t1会被阻塞,直到t2线程执行完,或join(millis)时间到,才会继续执行t1的run方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   | public class JoinDemo extends Thread { 	 	//子线程任务 	@Override 	public void run() { 		for(int i = 0; i < 50; i++) { 			 			System.out.println(getName() + " " + i); 		} 	} 	 	public static void main(String[] args) throws Exception { 		 		JoinDemo joinDemo = new JoinDemo(); 		 		for(int i = 0; i < 50; i++) { 			 			//主线程运行到i=20时被阻塞,开始执行50次子线程,然后继续执行主线程 			if(i == 20) { 				joinDemo.start(); 				joinDemo.join(); 				 			} 			System.out.println(Thread.currentThread().getName() + " " + i); 		} 	} }
  | 
 
sleep()和yield()区别
| 作用处 | 
sleep() | 
yield() | 
| 给其他线程执行机会 | 
会给其他线程执行机会,不会理会其他线程的优先级 | 
只会给优先级相同,或者优先级更高的线程执行机会 | 
| 影响当前线程的状态 | 
从阻塞到就绪状态 | 
直接进入就绪状态 | 
| 异常 | 
需要抛出 InterruptedException | 
不需要抛出任何异常 | 
Tread Dump(线程转储)
- 线程转储是一个JVM中活动线程的列表
 
- 它对分析系统的性能瓶颈和死锁非常有用
 
分析工具
- 有很多方法可以获取线程转储——使用Profiler,Kill -3命令,jstack工具等等
 
- jstack工具,因为它容易使用并且是JDK自带的
 
- 由于它是一个基于终端的工具,所以我们可以编写一些脚本去定时的产生线程转储以待分析