Thread 类本质上是实现了 Runnable 接口的一个实例,表明一个线程的实例。 启动线程的惟一方法就是经过 Thread 类的 start()实例方法。 start()方法是一个 native 方法,它将启动一个新线程,并执行 run()方法。数据库
public class MyThread extends Thread { public void run() { System.out.println("MyThread.run()"); } } MyThread myThread1 = new MyThread(); myThread1.start();
若是本身的类已经 extends 另外一个类,就没法直接 extends Thread,此时,能够实现一个Runnable 接口。编程
public class MyThread extends OtherClass implements Runnable { public void run() { System.out.println("MyThread.run()"); } }
有返回值的任务必须实现 Callable 接口,相似的,无返回值的任务必须 Runnable 接口。执行Callable 任务后,能够获取一个 Future 的对象,在该对象上调用 get 就能够获取到 Callable 任务返回的 Object 了。多线程
public class callableTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executor = Executors.newFixedThreadPool(10); //建立一个Callable,3秒后返回String类型 Callable myCallable = new Callable() { @Override public String call() throws Exception { // Thread.sleep(3000); System.out.println("calld方法执行了"); return "call方法返回值"; } }; List<Future> list = new ArrayList<Future>(); for (int i = 0; i < 10; i++) { Future future = executor.submit(myCallable); list.add(future); }
当线程被建立并启动之后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。
在线程的生命周期中,它要通过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5 种状态。尤为是当线程启动之后,它不可能一直"霸占"着 CPU 独自运行,因此 CPU 须要在多条线程之间切换,因而线程状态也会屡次在运行、阻塞之间切换。jvm
当程序使用 new 关键字建立了一个线程以后,该线程就处于新建状态,此时仅由 JVM 为其分配内存,并初始化其成员变量的值。ide
当线程对象调用了 start()方法以后,该线程处于就绪状态。 Java 虚拟机会为其建立方法调用栈和程序计数器,等待调度运行。工具
若是处于就绪状态的线程得到了 CPU,开始执行 run()方法的线程执行体,则该线程处于运行状态。this
阻塞状态是指线程由于某种缘由放弃了 cpu 使用权,也即让出了 cpu timeslice,暂时中止运行。spa
直到线程进入可运行(runnable)状态,才有机会再次得到 cpu timeslice 转到运行(running)状态。阻塞的状况分三种:线程
运行(running)的线程执行 o.wait()方法, JVM 会把该线程放入等待队列(waitting queue)中。code
运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池(lock pool)中。
运行(running)的线程执行 Thread.sleep(long ms)或 t.join()方法,或者发出了 I/O 请求时,JVM 会把该线程置为阻塞状态。当 sleep()状态超时、 join()等待线程终止或者超时、或者 I/O处理完毕时,线程从新转入可运行(runnable)状态。
线程会如下面三种方式结束,结束后就是死亡状态。
1.正常结束
run()或 call()方法执行完成,线程正常结束。
2.异常结束
线程抛出一个未捕获的 Exception 或 Error。
3.调用 stop
直接调用该线程的 stop()方法来结束该线程—该方法一般容易致使死锁,不推荐使用。
若是有一个对象在被多个线程同时竞争,那么判断对象是否有锁,若是有锁,那么会先支持偏向锁,就是说当前已经得到锁的线程会优先拿到锁(markword区记录了偏向线程id)。那么拿不到锁的线程,就会升级锁,变成CAS synchronized乐观锁,会进行一段时间的循环自旋不断尝试获取锁,当自旋到必定次数后,会再次升级成synchronized重量级锁。
锁方法会锁住this,锁静态方法会锁住class对象.锁代码块能够指定任意对象做为锁.
同步代码块可能会涉及到一个重入过程,synchronized不会说由于重入去不断重复获取锁释放锁的过程,而是用mointer每次重入去作一个计数器加一操做,在释放锁的过程当中也会逐步将计算器清零。而后让其余线程从block阻塞状态变成runnable状态去竞争这个锁。
synchronized不用手动编程,他是一个jvm关键字,我也不用关心他锁释放的一个过程,直接用就好了,而reentrantlock他是一个类,须要手动lock,配合try catch finally中去作一个锁释放操做
线程和数据库链接这些资源都是很是宝贵的资源。那么每次须要的时候建立,不须要的时候销毁,是很是浪费资源的。Java 里面线程池的顶级接口是 Executor,可是严格意义上讲 Executor 并非一个线程池,而只是一个执行线程的工具。真正的线程池接口是 ExecutorService。
一个线程池创建后,若是没有预加载任务,他一开始的核心线程数为0,当一个新任务被提交时,会创建一个核心线程去执行任务,若是一直来任务,而先前创建的核心线程都在忙,那么就会一直创建核心线程直到到达最大核心线程数。
但核心线程数最大,并且都在执行任务时,后来的任务会被放到blockingqueue(阻塞队列里),若是阻塞队列也满了,就会去创建新线程,此时的线程叫非核心线程,当整个线程池的线程数达到最大,他也有一个max access时,会触发拒绝策略。
AbortPolicy 停止策略
会直接抛出异常来执行停止任务执行拒绝
DiscardPolicy 抛弃策略
他会丢弃不执行多余的任务来执行拒绝
DIscardOldestPolicy
会丢弃最先你未执行的任务
callrunpolicy
在多线程环境下