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

来源:互联网 发布:linux 启动进程 start 编辑:程序博客网 时间:2024/05/16 06:47

一,简单回顾

线程的两种实现方式:
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;//注意到,接口的参数类型就是方法的返回类型
@Overridepublic 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() ;//测试线程是否被终止。此调用不会改变线程状态。

0 0
原创粉丝点击