【深入浅出java多线程】--基础准备篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_21443203/article/details/64920707

一,简单回顾

线程的两种实现方式:
1.继承Thread类(不推荐)–其实Thread类本身就是实现了Runnable接口

public class MyThread extends Thread{
    private static int i= 0;
    public MyThread(){
       i++;
    }
    @Override
    public void run() {
        System.out.println("创建第"+i+"个线程");
    }
}

2.实现Runnable接口

public class MyThread {
    public static void main(String[] args) {
        System.out.println("主线程ID:" + Thread.currentThread().getId());
        new Thread(new MyRunnable()).start();
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 只关心要做的任务
        System.out.println("子线程ID:" + Thread.currentThread().getId());
    }
}

或者直接这样:

    public static void main(String[] args) {
        System.out.println("主线程ID:" + Thread.currentThread().getId());
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("子线程ID:" + Thread.currentThread().getId());
            }
        };
        new Thread(runnable).start();
    }

结果都是:
主线程ID:1
子线程ID:9

二,线程状态

这里写图片描述

**- sleep,yield和wait的区别:
- sleep和yield是Thread类的静态方法,wait是Object类中定义的方法.
- Thread.sleep不会导致锁行为的改变, 如果当前线程是拥有锁的, 那么Thread.sleep不会让线程释放锁.
- wait()的作用是让当前线程由“运行状态”进入到“等待(阻塞)状态”,并释放同步锁。
- 而yield()的作用是让步,它让当前线程离开“运行状态”,进入到“就绪状态”。而且yield()方法不会释放锁。yield()只能使同优先级或更高优先级的线程有执行的机会。
- wait可以用notify/notifyAll方法唤醒,如果调用的是await,需要调用signal/signalAll来唤醒,两者只是名字不同,内部实现完全一样。**

三,使用Callable+Future/FutureTask

与Runnable不同的是,Callable**有返回结果**,其他用法一样,线程常用类都在java.util.concurrent并发包内。

public interface Callable<V> {
    //此接口里只有这一个方法
    V call() throws Exception;//注意到,接口的参数类型就是方法的返回类型
@Override
public Object call() throws Exception {
    // 我们可以看到返回的是Object,call与run方法内部实现一样,换了名字而已
    //do something...
    return null;
}

FutureTask实现了RunnableFuture接口,后者又分别继承了Runnable和Future接口,在线程中,用Future来接收线程的执行结果,jdk1.7中提供了可以操作线程或者查看线程状态的5个方法,分别是cancel,isCancelled,isDone,get和get的重写。但是其有个缺点,当多线程时,并不知道哪个线程先结束,为了提高性能,便有了FutureTask。它可以准确获取线程执行完成后返回的结果,此功能得益于它有一个回调函数protected void done(),当任务结束时,该回调函数会被触发。具体做什么,可以自己重载去实现。
e.g

package com.wz.test;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

public class AboutFuture {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();//稍后分析Executors的线程池框架
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                Random random = new Random();
                TimeUnit.SECONDS.sleep(random.nextInt(10));
                return Thread.currentThread().getName();
            }
        };
        for (int i = 0; i < 6; i++) {
            AboutFutureTask futureTask = new AboutFutureTask(callable);
            Future<?> future=executor.submit(futureTask);
            System.out.println("返回结果future:" + future);//返回结果future:java.util.concurrent.FutureTask@5193b022,这里只列出一条结果
        }
        executor.shutdown();
    }
}

class AboutFutureTask extends FutureTask<String> {
    public AboutFutureTask(Callable<String> callable) {
        //此处构造器是必需的
        super(callable);
    }
    @Override
    protected void done() {//重写FutureTask中的done()可以做自己想做的任务或者获取线程的信息
        try {
            System.out.println(get() + "当前线程已执行完毕!");
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

执行结果:
pool-1-thread-2当前线程已执行完毕!
pool-1-thread-5当前线程已执行完毕!
pool-1-thread-3当前线程已执行完毕!
pool-1-thread-4当前线程已执行完毕!
pool-1-thread-1当前线程已执行完毕!
pool-1-thread-6当前线程已执行完毕!

四,Thread其他常用方法(已过时的不列举)

  • public static native Thread currentThread();//返回当前运行的线程对象
  • public static void yield();//推荐静态调用;暂停当前线程对象,恢复到可执行状态,自己仍可以再次执行;

  • public final native boolean isAlive();//线程是否处于活动状态

  • public final void join();//让其他线程等待该线程结束

  • public final void join(long millis);//让其他线程等待该线程结束,最多等millis毫秒

  • 关于线程中断:
    public void interrupt() ;//向线程发出中断请求。
    public static boolean interrupted() ;//测试当前线程是否被中断。值得注意的是,这是个静态方法,调用它时会产生副作用—重置当前线程的中断状态为false,也就是说如果某个线程在中断情况下,调用了此方法,会将此线程唤醒。但是换个角度,如果当notifyAll()不起作用,也就是锁标志等待池中没有任何活动线程时,可以调用该方法,激活一个线程,从而去拯救其他线程。
    public boolean isInterrupted() ;//测试线程是否被终止。此调用不会改变线程状态。

猜你喜欢

转载自blog.csdn.net/qq_21443203/article/details/64920707