来自小马哥公开课java
归根到底new Thread()
并调用start()
是java建立并运行线程的惟一方式. Runnable
,Callable
以及继承 Thread
, 还有lamda表达式等相似代码其实都是线程的使用方式.数组
相比较而言, 建立进程的Java方式是使用Runtime#exec(String command)
方法实现.安全
Java正在执行的线程只有在执行完毕, 或者抛出异常后才能中止. 也就是基本能够认为: 线程一旦开始执行就没法从外部控制其销毁.多线程
Thread#stop()
方法用来中止线程, 但此方法过于暴力, 可能会致使资源不会正确释放, 会致使死锁, 此方法已经标记为过时.jvm
while(true)
循环类线程可使用interrupt()
方法经过抛出InterruptedException
来结束线程, 但要注意只有线程阻塞状况下才会抛出此异常, 所以, 对于非阻塞状态的线程, 是使用isInterrupted()
方法来判断中断标志来结束控制循环.ide
while(!isInterrupted()){ try{ Thread.sleep(5000); }catch(InterruptedException e){ e.pringStackTrace(); break; } }
使用状态标志变量中止方式以下:工具
class TaskThread implements Runnable{ private volatile boolean stoped = fasle; // 标识字段, 注意线程安全问题, 使用volatile保证可见性 @Override public void run(){ if(!stopped){ // todo } } public void setStoped(boolean stop){ stoped=stop; } }
join()
join()
方法会阻塞调用它的线程. 方法的关键代码以下:性能
public final synchronized void join(long millis){ while (isAlive()) { wait(millis); } }
可见其最终是使用Object#wait(long millis)
来实现, 也就是说, 咱们本身也可使用Object#wait()
来控制线程的执行顺序.ui
ExecutorService singlePool = Executors.newSingleThreadExecutor() singlePool.submit(t1); singlePool.submit(t2); singlePool.shutdown();
CountdownLatch
t1.start() while(t1.isAlive()){ //Thread.sleep(5); } t2.start();
Thread.sleep(long millis)
Java只能捕获unchecked异常. 线程异常时线程即终止.线程
可使用下面方式捕获线程抛出的异常, 这样作的话线程的异常堆栈将不会输出到System.error标准输出流.
对于堆栈过多的场景来自定义错误handler处理, 能够防止错误堆栈致使内存耗尽. Spring boot 中的SpringApplication有相关的接口.
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh);
除了上面的方法, 还可使用以下方法捕获异常.
ThreadPoolExecutor#afterExecute(Runnable r, Throwable t)
NEW 新建线程 new
RUNABLE 可运行, start()
BLOCKED 阻塞, 获取锁
WAITING 等待
TIME_WAITING 超时等待
TERMINATED 终结
jstack pid
能够显示出全部线程.ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); long[] ThreadIds = threadMXBean.getAllThreadIds(); for(long threadId : ThreadIds){ ThreadInfo threadInfo =ThreadMXBean.getThreadInfo(threadId); }
synchronized 在方法和代码块上的区别,能够查看字节码文件. 关注monitorenter和monitorexit指令, 方法的话关注其flag的标志位.
两者都可重入. ReentrantLock 多了三个功能, 可中断, 公平锁, 绑定多个Condition. ReentrantLock 性能可能更高一点, 也有更多的控制, 好比尝试得到锁, 释放等, 同时也能够绑定多个条件.
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // 当前的state if (c == 0) { //首次获取到锁 if (compareAndSetState(0, acquires)) { //CAS并设置状态 setExclusiveOwnerThread(current); //线程暂存 return true; } } else if (current == getExclusiveOwnerThread()) { //断定是否存储当前线程, 是的话就是重入 int nextc = c + acquires; //状态新增 if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); //状态回写 return true; } return false; }
wait()
和 notity()
notifyAll()
在 Object 中定义的缘由?一个很明显的缘由是JAVA提供的锁是对象级的而不是线程级的,每一个对象都有锁,经过线程得到。锁是线程争用的对象, 与线程不该该过分链接. Object上也有一些头信息, 为锁的管理提供方便.
wait()
和 notity()
为何必须在 synchronized 中执行?很简单, 多线程环境下的锁才有意义, synchronized 代表有资源争用, 即锁的争夺, 这是锁存在的前提.
关于这个问题, 其实是一个depands-on的答案, 有时候子线程会继续执行一段时间, 有时候则在主线程退出后当即退出, 通常认为主线程退出后台线程也会退出, 但并不能认为子线程必定不会执行.
方法签名: Runtime#addShutdownHook(Thread thread)
这个钩子方法能够在线程退出时回调完成一些工做, 好比资源回收,还有一些对象的销毁工做.
ThreadGroup
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); int count = threadGroup.activeCount(); Thread[] threads = new Thread[count]; threadGroup.enumerate(threads,true); //复制到这个数组 for (Thread t : threads) { System.out.println(t.getState()); }