线程驱动任务,而咱们须要的就是一种任务的描述,而这个描述由Runable接口来提供,想定义任务,只须要实现Runable接口并重写里面的run()就好
java
方法名 | 描述 |
---|---|
Thread() | 建立新线程对象 |
Thread(String name) | 建立新线程对象 |
Thread(Runnable target) | 建立新线程对象 |
Thread(Runnable target, String name) | 建立新线程对象,name为指定的线程名 |
Thread(ThreadGroup group, Runnable target) | 分配新的 Thread 对象。 |
Thread(Runnable target) | 建立新线程对象 |
Thread构造器一般须要一个Runable对象,咱们把须要执行的任务放在run()中,程序运行后,会自动执行Runable对象的run()方法,以便在新的线程中执行咱们指定的任务. start()方法是告诉cpu线程处于就绪状态算法
public class demo01 extends Thread { public demo01(String name){ super.setName(name); } public demo01(){ } @Override public void run() { while(true) System.out.println(Thread.currentThread().getName()+"继承Thread类的线程执行了..."); } public static void main(String[] args) { //new demo01() 执行Thread空参构造方法... demo01 d = new demo01(); demo01 d2 =new demo01("helloThread"); //线程就绪 d.start(); d2.start(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } }
实现runable接口 其实demo02 本类并非一个Thread 他是一个线程任务编程
public class demo02 implements Runnable{ @Override public void run() { // while(true) System.out.println(Thread.currentThread().getName()+"线程执行了..."); } public static void main(String[] args) { demo02 d = new demo02(); Thread myThread = new Thread(d); myThread.start(); //lamaban表达式实现的run方法 new Thread(()->{ while(true) System.out.println("lamaban表达式实现的run方法执行了..."); } ).start(); //直接写 new Thread(){ @Override public void run() { System.out.println("hello Thread.."); } }.start(); //实现Runable() + 继承Thread(); new Thread(new Runnable() { @Override public void run() { System.out.println("Runnable接口里面的run"); } }){ //子类覆盖了 父类的run方法... @Override public void run(){ System.out.println("Thread子类里面的run"); } }.start(); } }
通常状况下,若是不是多继承,实现Runable接口和继承Thread类没啥区别api
Callable一样能够理解成是一个任务的描述方式,只不过他不能直接丢给Thread,而是交给一个叫FutrueTask的容器包装,多线程
Callable更强大一些.运行Callable的任务,能够拿到一个Future的对象,咱们能够先经过这个对象isDone()判断任务是否结束,而后调用get()获取运行的返回值异步
一来讲多个线程之间是异步执行的,咱们很难从一条线程拿到另外一条线程的返回值,这个时候Futrue就出场了,对于Callable和Runable提交过来的任务,他能够进行查询任务是否完成 isDone() 获取执行结果get() 取消任务cancel()ide
此外咱们能够知道它最终也是执行Callable类型的接口,若是传递进来的是Runable的实现,那么它会先把他转化成Callable,函数
public class demo03 implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("hello Callable"); //返回值的类型就是Callable接口的泛型 return 1; } public static void main(String[] args) throws ExecutionException, InterruptedException { //将来的任务 FutureTask<Integer> task = new FutureTask<>(new demo03()); new Thread(task).start(); System.out.println("返回值的结果是:"+task.get()); } }
刚才提到,Thread接收的任务是Runable类型的,如今FutureTask是个什么鬼?怎么把它传递进来的? 其实,FutrueTask实现了RunnableFuture接口,而这个接口继承了Runnable&Future,一切也就那么顺其天然了this
固然咱们知道,Runable里面的run()方法是由新new出来的线程异步执行的,那么如今重写的这个call()怎么个运行法?操作系统
查看FutrueTask的源码,咱们能够看到,call()是由FetureTask的run()执行的,
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true;
run()方法&call()方法
Runable的Run方法 是由 线程异步调用的
虽然是耗时的操做,若是可能出现阻塞,由新的线程中执行,会节省时间
Callable的 call 方法,同步调用的,是由Future的run方法调用的,而这个run方法,是对Runable接口里面run()的重写
依然是耗时的操做
在往线程池中提交任务时 submit()方法一样可接受Callable对象,后续会详解
Future<String> future = threadPoolExecutor.submit(new Callable<String>() { @Override public String call(){ ai.getAndIncrement(); return Thread.currentThread().getName(); } });
interrupted():
它要配合 isInterrupted() ,做为条件,判断当前的状态,去中断, 本函数屡次调用不会 改变 当前线程的状态
实例代码
/* * 中止不了的线程 * */ public class CanNotStop extends Thread{ AtomicInteger value = new AtomicInteger(1); @Override public void run() { value.getAndIncrement(); System.out.println("当前的value== "+value); /* * isInterrupted() 方法, 判断当前线程的状态去中断线程, * 假如说,当前线程被标记为要去中断, 被isInterrupted()限制的Target方法再也不执行,条件以外的代码,能且只能执行一次! 而后完全被中断 * */ while(!isInterrupted()) { try { sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } try { sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "执行了.."); } System.out.println("你真的觉得我被中断了吗?"); } public static void main(String[] args) { //初始化 CanNotStop canNotStop = new CanNotStop(); CanNotStop canNotStop2 = new CanNotStop(); canNotStop.start(); canNotStop2.start(); /* * 关于interrupt()方法,这个方法 * 做用: * 中断当前线程,可是! 相比于废弃的stop() 并非真正意义上的中断,而是打上了一个标记, 表示想要中断它.可是呢?在中断它以前要让他把该作的事, * 该跑的代码 跑完! * 特性: * 第一次执行interrupt()----> 标记当前线程是要被中断的 * 第二次执行interrupt()----> 清除全部标记 * * 它要配合 isInterrupted() ,做为条件,判断当前的状态,去中断, 本函数屡次调用不会 改变 当前线程的状态 * */ canNotStop.interrupt(); try { sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } //被中断就至关于死掉了? synchronized (canNotStop){ canNotStop.notifyAll(); } } }
这也称做是中止不了的线程,为啥这样说呢? 能够看到,执行 canNotStop.interrupt();代码的是谁? 没错主线程!细想一下,执行这个语句时,新建立的线程,原本就没有抢到CPU的执行权,也就是说他原本就是中止的... 他的原理就是打个标记,等到被打上标记的线程抢到CPU的执行权的时候,去判断一下就好了,若是存在被中断的标记,就什么事都不作,反之则执行任务.其实,它还活着
返回当前代码,正在被哪一个线程调用
判断当前线程是否处于存活状态,线程处于正在运行或者等待运行的状态返回true,线程运行完毕返回false
指定在线程休眠的时间,在指定的时间后,从新进入就绪状态去竞争CPU的执行权
返回线程的id & 名字
throw new InterruptedException();
@Override public void run(){ while(true){ if(this.isInterrupted()){ return; } System.out.println("if 后面的代码"); } }
推荐使用的是剖出异常的中止线程的方法,由于有了异常以后,能够在catch块中对异常进行处理,让程序更加流畅
线程的优先级用处是,把任务的重要性告诉调度器,让任务的调度器,更倾向于优先级高的线程先执行,可是也存在优先级底的线程先执行的可能
在<
>提到,在绝大多数状况下,都应该使线程按照默认的优先级规则执行,试图操做优先级让线程先执行,一般是一种错误
此外,jdk中线程的优先级有是个,可是和操做系统都不能映射的很好,好比Windows系统是七个优先级,因此通常咱们使用的是 MAX_PRIORITY NORM_PRIORITY MIN_PRIORITY
setPriority(int newPriority);
其中newPriority的值由1-10 ,若不在这个范围内,抛出IllegalArgumentExeception()
getPriority();
特性:
设置为守护线程, 它确定会随着主线程的退而退出
java线程中有两类,一类是用户线程(非守护线程) 一类是守护线程. 它的特性就是 伴随,去守护用户线程,
好比 java的GC(垃圾回收算法) 就是一个很称职的守护者!
setDaemon(true);
public class demo02 implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread thread = newThread(r); thread.setDaemon(true); return thread; } }
ExecutorService executorService = Executors.newCachedThreadPool(new demo02());
当再没有非守护线程后,守护线程中run方法中的finally代码块是不会执行而直接退出
参考书籍<