总览
- Java中的进程和线程
- 运行一个程序会产生一个进程,进程包含至少一个线程(主线程)
- 每个进程对应一个JVM实例,多个线程共享JVM里的堆
- 主线程可以创建子线程,主线程原则上要后于子线程完成执行(各种关闭动作在主线程中执行)
java线程(Thread)
-
Thread的
start()
和run()
- 调用
start()
会创建一个新的子进程并启动,run()
只是Threa对象的普通方法调用
注:由源码可得,start()
会创建一个线程,然后去执行run()
方法里的内容 - Java线程创建关系图
- 调用
-
Thread
和Runnable
Thread
是类,Runnable
是接口Thread
类实现了Runnable
接口Runnable
只有一个抽象run()
方法(Runnable
不具有多线程的特性)
-
java线程的创建
- 继承
Thread
类,并重写run()
方法(线程中的逻辑在run()
方法中实现)public class MyThread extends Thread { private String name; public MyThread(String name){ this.name = name; } @Override public void run(){ for(int i = 0 ; i < 10 ; i ++){ System.out.println("Thread start : " + this.name + ",i= " + i); } } } public class ThreadDemo { public static void main(String[] args) { MyThread mt1 = new MyThread("Thread1"); mt1.start(); } }
- 实现
Runnable
接口
原理:Thread
带参构造函数中,可以传递Runnable
,且调用Thread
的run()
方法会调用Runnable
中的run()
方法
public class MyRunnable implements Runnable { private String name; public MyRunnable(String name){ this.name = name; } @Override public void run(){ for(int i = 0 ; i < 10 ; i ++){ System.out.println("Thread start : " + this.name + ",i= " + i); } } } public class RunnableDemo { public static void main(String[] args) throws InterruptedException { MyRunnable mr1 = new MyRunnable("Runnable1"); Thread t1 = new Thread(mr1); t1.start(); } }
- 补充:给
run()
方法传参- 构造方法传参
- 成员变量传参
- 回调函数传参
- 继承
-
java线程返回值的处理
- 主线程等待法
Thread.currentThread().sleep(500);
- 使用
Thread
类的join()
阻塞当前线程以等待子线程处理完毕public class CycleWait implements Runnable{ private String value; public void run() { try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } value = "we have data now"; } public static void main(String[] args) throws InterruptedException { CycleWait cw = new CycleWait(); Thread t = new Thread(cw); t.start(); // while (cw.value == null){ // Thread.currentThread().sleep(100); // } t.join(); System.out.println("value : " + cw.value); } }
- 通过
Callable
接口实现:通过FutureTask
或者线程池
获取FutureTask
注:FutureTask
实现了Runnable
- 判断
Callable
中的call
方法是否执行完毕 - 若
call
方法执行完毕,则返回,否则阻塞当前进程
- 带参
get
,增加了超时机制
//实现callable public class MyCallable implements Callable<String> { @Override public String call() throws Exception{ String value="test"; System.out.println("Ready to work"); Thread.currentThread().sleep(5000); System.out.println("task done"); return value; } } //通过FutureTask完成等待 public class FutureTaskDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> task = new FutureTask<String>(new MyCallable()); new Thread(task).start(); if(!task.isDone()){ System.out.println("task has not finished, please wait!"); } System.out.println("task return: " + task.get()); } } //通过线程池等待 public class ThreadPoolDemo { public static void main(String[] args) { ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); Future<String> future = newCachedThreadPool.submit(new MyCallable()); if(!future.isDone()){ System.out.println("task has not finished, please wait!"); } try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } finally { newCachedThreadPool.shutdown(); } } }
sleep
和wait
方法sleep
sleep
是Thread
类的方法- 可以在任何地方调用
sleep
方法只会让出CPU,不会释放锁
wait
wait
是Object
类中定义的方法- 只能在
synchronized
方法或synchronized
块中使用 wait
方法会让出CPU,也会释放已经占有的同步锁
public class WaitSleepDemo { public static void main(String[] args) { final Object lock = new Object(); new Thread(new Runnable() { @Override public void run() { System.out.println("thread A is waiting to get lock"); synchronized (lock){ try { System.out.println("thread A get lock"); Thread.sleep(20); System.out.println("thread A do wait method"); lock.wait(); System.out.println("thread A is done"); } catch (InterruptedException e){ e.printStackTrace(); } } } }).start(); try{ Thread.sleep(10); } catch (InterruptedException e){ e.printStackTrace(); } new Thread(new Runnable() { @Override public void run() { System.out.println("thread B is waiting to get lock"); synchronized (lock){ try { System.out.println("thread B get lock"); System.out.println("thread B is sleeping 10 ms"); Thread.sleep(10); lock.notifyAll(); Thread.yield(); Thread.sleep(2000); System.out.println("thread B is done"); } catch (InterruptedException e){ e.printStackTrace(); } } } }).start(); } }
- 线程的中断
- 调用
interrupt()
通知线程中断
- 线程中应该做的处理
public class InterruptDemo { public static void main(String[] args) throws InterruptedException { Runnable interruptTask = new Runnable() { @Override public void run() { int i = 0; try { //在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程 while (!Thread.currentThread().isInterrupted()) { Thread.sleep(100); // 休眠100ms i++; System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") loop " + i); } } catch (InterruptedException e) { //在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。) System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") catch InterruptedException."); } } }; Thread t1 = new Thread(interruptTask, "t1"); System.out.println(t1.getName() +" ("+t1.getState()+") is new."); t1.start(); // 启动“线程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is started."); // 主线程休眠300ms,然后主线程给t1发“中断”指令。 Thread.sleep(300); t1.interrupt(); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted."); // 主线程休眠300ms,然后查看t1的状态。 Thread.sleep(300); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now."); } }
- 调用
- 线程状态图
- 主线程等待法