目录页:https://blog.csdn.net/u011294519/article/details/88367808
1.简单的基础知识
(PS:网上很多很全,写在这里只是显得有章法(o´罒`o)哼):
进程和线程的区别:
- 进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源
- 线程:CPU调度的最小单位
并行和并发的区别:
- 并行:同一时刻可以处理事务的能力
- 并发: 与时间单位相关,在单位时间内可以处理事务的能力
撸代码阶段:
2.开胃菜
先来个开胃菜,使用虚拟机管理接口查看线程
import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean;
/** * *类说明:展示线程 */ public class ShowThread { public static void main(String[] args) { //虚拟机线程管理的接口 ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false); for(ThreadInfo threadInfo:threadInfos) { System.out.println("["+threadInfo.getThreadId()+"]"+" " +threadInfo.getThreadName()); } } } |
代码在sharing-collaboration模块中
运行结果如下
Monitoring Thread参照Oracle官方文档:
https://docs.oracle.com/cd/E13188_01/jrockit/docs50/userguide/apstkdmp.html
其他线程想了解的参照:http://ifeve.com/jvm-thread/
3.线程启动
简单的线程启动方式(这里简单的意思是不考虑线程池):继承Thread类,实现Runnable接口和Callable接口。
实现Runnable接口和Callable最大的区别就是Runnable无返回值,Callable有返回值。
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;
/** * *类说明:如何新建线程 */ public class NewThread {
/** * 实现Runnable接口 */ private static class UseRun implements Runnable{
@Override public void run() { System.out.println("I am implements Runnable"); }
}
/** * 实现Callable接口,允许有返回值 */ private static class UseCall implements Callable<String>{
@Override public String call() { System.out.println("I am implements Callable"); return "CallResult"; }
}
public static void main(String[] args) throws InterruptedException, ExecutionException { /* 真实项目中启动线程最好使用线程池, 否则有可能导致创建大量同类线程消耗完内存, 也会增加线程间切换的成本(有可能切换时间比程序执行时间还要长) */ UseRun useRun = new UseRun(); new Thread(useRun).start();
// Thread不支持Callable,所以借用FutureTask UseCall useCall = new UseCall(); FutureTask<String> futureTask = new FutureTask<>(useCall); new Thread(futureTask).start(); System.out.println(futureTask.get()); } } 代码在sharing-collaboration模块part1 |
4.线程停止
- stop()不建议使用,因为无法保证线程资源被完全释放
- suspend()和resume()方法:
这两个方法是配对使用的,suspend()方法就是将一个线程挂起(暂停),不会释放资源,会造成死锁;resume()方法就是将一个挂起线程复活继续执行。
interrupt()是建议使用的停止线程的方法。Java线程是协作式的,interrupt()并不是强行关闭当前线程,而是打个招呼,将该线程的中断标志位设置为true。isInterrupted()方法用于判断当前线程是否处于中断状态。
package com.concurrent.coline.part1.end;
/** *类说明:中断Runnable类型的线程 */ public class EndRunnable {
private static class UseRunnable implements Runnable{
@Override public void run() {
String threadName = Thread.currentThread().getName(); while(!Thread.currentThread().isInterrupted()) { System.out.println(threadName+" is run!"); } System.out.println(threadName+" interrput flag is " +Thread.currentThread().isInterrupted()); } }
public static void main(String[] args) throws InterruptedException { UseRunnable useRunnable = new UseRunnable(); Thread endThread = new Thread(useRunnable,"endThread"); endThread.start(); Thread.sleep(20); endThread.interrupt(); }
} 运行结果: |
代码在sharing-collaboration模块part1 |
InterruptedException异常(很纠结要不要放在这里说,想了下InterruptedException也是和线程停止相关的):线程抛出 InterruptedException异常时会将线程中断标志位复位,即设置为true,线程无法停止。
package com.concurrent.coline.part1.end;
import java.text.SimpleDateFormat; import java.util.Date;
/** * *类说明:抛出InterruptedException异常的时候,要注意中断标志位 */ public class HasInterrputException {
private static SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss_SSS");
private static class UseThread extends Thread{
public UseThread(String name) { super(name); }
@Override public void run() { String threadName = Thread.currentThread().getName(); while(!isInterrupted()) { try { System.out.println("UseThread:"+formater.format(new Date())); Thread.sleep(3000); } catch (InterruptedException e) { System.out.println(threadName+" catch interrput flag is " +isInterrupted()+ " at " +(formater.format(new Date()))); // 测试的时候可以把这个注释打开看看 // interrupt(); e.printStackTrace(); } System.out.println(threadName); } System.out.println(threadName+" interrput flag is " +isInterrupted()); } }
public static void main(String[] args) throws InterruptedException { Thread endThread = new UseThread("HasInterrputEx"); endThread.start(); System.out.println("Main:"+formater.format(new Date())); Thread.sleep(800); System.out.println("Main begin interrupt thread:"+formater.format(new Date())); endThread.interrupt();
}
} |
5.线程优先级
线程优先级:1~10,缺省为5,但是线程优先级取决于操作系统,所以只需要了解下。
6.守护线程
守护线程与主线程同生共死,注意:守护线程的finally代码块中的内容不一定会执行
package com.concurrent.coline.part1.daemon;
/** * 守护线程 */ public class DaemonThread { private static class DemoThread extends Thread { @Override public void run() { try { String threadName = Thread.currentThread().getName(); while(!isInterrupted()){ System.out.println(threadName+" is running"); } System.out.println(threadName+" interrput flag is " +Thread.currentThread().isInterrupted());
} finally { // 守护线程中finally不一定会执行 System.out.println("attention this part is not run in daemon thread"); } } }
public static void main(String[] args) throws InterruptedException { //守护线程,与主线程(main)同生共死 DemoThread demoThread = new DemoThread(); // 设置为守护线程,必须要在start之前 demoThread.setDaemon(true); demoThread.start(); Thread.sleep(10); //demoThread.interrupt(); } } |
运行结果:
代码在sharing-collaboration模块的part1