Java 并发编程 ---Java 多线程基本概念,java 高并发编程详解 pdf 百度网盘
我们在学习 Java 的时候,Java 是一个面向对象的语言,所有类的父类是那个是 Object,在 Object 里有这样一个方法
我们一个对象在有资源要回收的时候,会重写这个方法,然后将回收资源的操作,放到这个方法里面执行,这个方法就会由 Finalizer 这个线程执行,但是有的时候会发现,这个 finalize 方法不一定会执行,导,有些关于对象的资源就会没有被回收掉,为什么会这样呢?这个锅得 Finalizer 线程来背了,是因为 Finalizer 这个线程是一个守护线程,和主线程同生共死,极有可能主线程挂掉了 finalize 这个方法还没来得及执行,然后 Finalizer 也挂掉了
2.1 启动线程的两种方式
Java 里的程序天生就是多线程的,新启动线程的方法有:
Thread 类
实现接口 Runnable
实现接口 Callable 有返回值
/***
启动线程的几种方式*/public class NewThread {//继承自 Thread 类 private static class UseThread extends Thread{@Overridepublic void run() {super.run();System.out.println("UseThread:我运行了");}}//实现 runnable 接口 private static class UseRun implements Runnable{
@Overridepublic void run() {System.out.println("UseRun:我运行了");}}//实现 callable 接口,允许有返回值 private static class UseCall implements Callable<String>{@Overridepublic String call() throws Exception {System.out.println("UseCall:我运行了");return "CallResult";}}public static void main(String[] args) throws ExecutionException, InterruptedException {UseThread useThread=new UseThread();useThread.start();UseRun useRun=new UseRun();new Thread(useRun).start();UseCall useCall=new UseCall();FutureTask<String> futureTask=new FutureTask<>(useCall);new Thread(futureTask).start();System.out.println(futureTask.get());}}
Callable 和 Runnable 实现的方法其实可以看做一
种方式,因为在启动线程的时候 Callable 是放到 FutureTask 里面的,我们去看看 FutureTask 是什么东西他是个泛型类,实现了 RunnableFuture 这个泛型接口,RunnableFuture 这个接口又继承了 Runnable,和 Future,所以我们可以把 Runnable 和 Callable 看成一种方式,Callable 这种方式是怎么拿到返回值的呢?
futureTask.get()拿到就是返回值,首先我们看一看 Future 这个接口都有什么方法
我们再去看实现
它会先判断这个任务执行的状态是否完成,如果没有完成它会进入等待完成这个方法
private int awaitDone(boolean timed, long nanos)throws InterruptedException {final long deadline = timed ? System.nanoTime() + nanos : 0L;WaitNode q = null;boolean queued = false;for (;;) {if (Thread.interrupted()) {removeWaiter(q);throw new InterruptedException();}
int s = state;if (s > COMPLETING) {if (q != null)q.thread = null;return s;}else if (s == COMPLETING) // cannot time out yetThread.yield();else if (q == null)q = new WaitNode();else if (!queued)queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);else if (timed) {nanos = deadline - System.nanoTime();if (nanos <= 0L) {removeWaiter(q);return state;}LockSupport.parkNanos(this, nanos);}elseLockSupport.park(this);}}
它会一直等待执行完成 完成之后它会 执行 report 方法,咱再看 report 方法
然后我们再去看看 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;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result);}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner = null;// state must be re-read after nulling runner to prevent// leaked interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}
它会把 Call 的返回值通过 set 方法赋值给 outcome,get 的时候再把 outcome 返回回去
protected void set(V v) {if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {outcome = v;UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final statefinishCompletion();}}
这样就 能拿到 Callable 的返回值了,在这里我们要区分 Thread 和 Runnable,Thread 是唯一一个对操作系统线程的抽象,而 Runnable 和 Callable 是对任务的抽象,一定要区分
2.2 线程安全的停止工作
有开始就有结束,怎样才能让 Java 里的线程安全的停止工作呢 stop()还是 isInterrupted( ),static 方法 interrupted()?我们要深了解这些方法 一般情况下,Thread 的 run 方法执行完毕,或者 抛出了异常,这个线程就在执行完毕,自己就停止了,这是一般情况下,但是我们往往因为业务的需求,需要在满足某种条件的时候,去手动停止这个线程,这个时候我们应该怎么办呢?首先我们还是去看代码去看看 Thread 里有什么方法
我们看到了 stop(),destroy(),还有 suspend(),但是他们都被 @Deprecated 注解了,JDK 就告诉我们这几个方法就不要用 线程的挂起函数 suspend(),这个线程在执行挂起的时候,线程不会释放资源,比如它在执行的时候拿到一个锁,挂起的时候他不会释放这个锁,这样就很有可能会导致死锁的问题 线程的停止函数 stop(),这个函数是极其野蛮的,你调用这个函数,他会立马把这个线程干掉,他不会 管你这个线程的资源是否正常的释放,比如你在一个线程里写一个文件,写到一半的时候你调用这个方法,造成文件不能正常结束,而且线程里占据操作系统的资源文件句柄啥的没有得到释放 resume 是唤起挂起线程的,和 suspend 配对使用的 其实我们在终止线程的时候,有这么几个方法可以用
interrupt 是终止线程,interrupted,isInterrupted 是获取线程是否终止 ,interrupt 终止线程是一种协作方式不是那种抢占式,话不多说上代码,
public class EndThread {private static class UseThread extends Thread{@Overridepublic void run() {super.run();while(true){System.out.println("EndThread:emmmmmm");}}}
public static void main(String[] args) throws InterruptedException {UseThread useThread=new UseThread();useThread.start();Thread.sleep(30);useThread.interrupt();}}
这段代码是在主线程里面新启动一个线程,主线程休眠 30ms 去调用 useThread 的 interrupt(),结果怎么样,结果 useThread 根本不鸟你,一直在执行,我们把代码做一下更改
private static class UseThread extends Thread{@Overridepublic void run() {super.run();// while(true){System.out.println("EndThread:"+isInterrupted());while(!isInterrupted()){System.out.println("EndThread:emmmmmm");
评论