Java

学习Java线程

Imagem de capa

线程的概念

百度百科的解释

维基百科的解释

线程状态

疑问

补充

线程创建的方式

继承Thread类

package com.thread.demo;

/**
 * @Author yudong
 * @Date 2018年06月20日 上午10:47
 */
public class ThreadTest extends Thread{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        System.out.println("线程完成启动");
    }

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        threadTest.start();
    }
}
Thread-0
线程完成启动

Process finished with exit code 0

实现Runnable接口

package com.thread.demo;

/**
 * @Author yudong
 * @Date 2018年06月20日 上午10:54
 */
public class RunnableTest implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        System.out.println("线程完成启动");
    }


    public static void main(String[] args) {
        RunnableTest runnableTest = new RunnableTest();
        Thread thread = new Thread(runnableTest);
        thread.start();
    }
}

Thread-0
线程完成启动

Process finished with exit code 0

查看Thread源码,会发现Thread是实现了Runnable接口的(JDK1.8源码),如下是Runnable片段

public
class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private volatile String name;
    private int            priority;
    private Thread         threadQ;
    private long           eetop;
   ......
}

查看Thread源码,会发现Thread的多种构造方法(JDK1.8源码),如下是Thread片段

/**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, null, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     */
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

    /**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, target, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     *
     * @param  target
     *         the object whose {@code run} method is invoked when this thread
     *         is started. If {@code null}, this classes {@code run} method does
     *         nothing.
     */
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

    /**
     * Creates a new Thread that inherits the given AccessControlContext.
     * This is not a public constructor.
     */
    Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
    }

    /**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (group, target, gname)} ,where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     *
     * @param  group
     *         the thread group. If {@code null} and there is a security
     *         manager, the group is determined by {@linkplain
     *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
     *         If there is not a security manager or {@code
     *         SecurityManager.getThreadGroup()} returns {@code null}, the group
     *         is set to the current thread's thread group.
     *
     * @param  target
     *         the object whose {@code run} method is invoked when this thread
     *         is started. If {@code null}, this thread's run method is invoked.
     *
     * @throws  SecurityException
     *          if the current thread cannot create a thread in the specified
     *          thread group
     */
    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }

Thread类实例化后不允许克隆(JDK1.8源码),如下是Thread片段

 /**
     * Throws CloneNotSupportedException as a Thread can not be meaningfully
     * cloned. Construct a new Thread instead.
     *
     * @throws  CloneNotSupportedException
     *          always
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

Thread 多次调用 thread.start() 方法会有什么结果

/**
 * @Author yudong
 * @Date 2018年06月20日 上午10:54
 */
public class RunnableTest implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        System.out.println("线程完成启动");
    }


    public static void main(String[] args) {
        RunnableTest runnableTest = new RunnableTest();
        Thread thread = new Thread(runnableTest);
        thread.start();
        thread.start();
    }
}
objc[70590]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java (0x10e3994c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x10f3c44e0). One of the two will be used. Which one is undefined.
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Thread.java:708)
	at com.thread.demo.RunnableTest.main(RunnableTest.java:19)
Thread-0
线程完成启动
 /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

线程池

ThreadPoolExecutor Executors

package com.thread.demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author yudong
 * @Date 2018年06月20日 下午1:45
 */
public class ExecutorServiceTest {

    public static void main(String[] args) {
        //创建指定数量的线程池
        ExecutorService  es = Executors.newFixedThreadPool(10);
        //创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
        ExecutorService  es1 = Executors.newCachedThreadPool();
        //创建一个单线程化的Executor,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
        ExecutorService  es2 = Executors.newSingleThreadExecutor();
        //创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类,配置核心线程数量
        ExecutorService  es3 = Executors.newScheduledThreadPool(10);
        //创建持有足够线程的线程池来支持给定的并行级别,并通过使用多个队列,减少竞争,它需要穿一个并行级别的参数,如果不传,则被设定为默认的CPU数量
        ExecutorService  es4 = Executors.newWorkStealingPool();
        Runnable task = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
                System.out.println("线程完成启动");
            }
        };
        es.execute(task);
    }
}

ForkJoinPool

package com.thread.demo;

import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;

/**
 * 带返回值的
 * @Author yudong
 * @Date 2018年06月20日 下午2:37
 */
public class ForkJoinPoolTest extends RecursiveAction {

    //任务容器,可以为一个对象
    private int task = 0;

    //构造方法用于传入数据对象
    public ForkJoinPoolTest(int task) {
        this.task = task;
    }

    @Override
    protected void compute() {
        //是否分发的条件,这里是如果任务量大于20,就分解成两个小任务执行
        if (task <=20){
            System.out.println(Thread.currentThread().getName()+"承担了"+task+"份工作");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            Random m = new Random();
            int x = 20;
            ForkJoinPoolTest n1 = new ForkJoinPoolTest(x);
            ForkJoinPoolTest n2 = new ForkJoinPoolTest(task - x);
            n1.fork();
            n2.fork();
        }
    }

    public static void main(String[] args) {
        //创建一个支持分解任务的线程池ForkJoinPool
        ForkJoinPool pool=new ForkJoinPool();
        ForkJoinPoolTest n1 = new ForkJoinPoolTest(52);
        pool.submit(n1);
        pool.awaitQuiescence(20, TimeUnit.SECONDS);
        pool.shutdown();
    }
}

ForkJoinPool-1-worker-3承担了20份工作
ForkJoinPool-1-worker-2承担了20份工作
ForkJoinPool-1-worker-1承担了12份工作

Process finished with exit code 0
package com.thread.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * 计算一组数的总和
 * @Author yudong
 * @Date 2018年06月20日 下午3:26
 */
public class ForkJoinPool2Test extends RecursiveTask<Integer> {

    private List<Integer> number = new ArrayList<>();

    public ForkJoinPool2Test(List<Integer> number) {
        this.number = number;
    }

    @Override
    protected Integer compute() {
       //如果这一组数超过了5个,分发下去
        int sum=0;
        int size = number.size();
        if (size<5){
            for (int i =0;i<size;i++){
                sum=sum+number.get(i);
            }
            try {
            Thread.sleep(200L);
            }catch (Exception e){
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"求和完了:"+sum);
            return sum;
        }else{
            ForkJoinPool2Test  f1  = new ForkJoinPool2Test(number.subList(0,4));
            ForkJoinPool2Test  f2  = new ForkJoinPool2Test(number.subList(4,number.size()));
            f1.fork();
            f2.fork();
          return f1.join()+f2.join();
        }
    }

    public static void main(String[] args) throws Exception{
        //初始化一个list,让里面包含1-100的值
        List<Integer> number = new ArrayList<>();
        for (int i = 1;i<=100;i++){
            number.add(i);
        }
        Long time = System.currentTimeMillis();
        ForkJoinPool2Test f = new ForkJoinPool2Test(number);
        //这里面是求和处理
        ForkJoinPool pool=new ForkJoinPool(50);
        Integer sum  = 0;
        sum = pool.submit(f).get();
        System.out.println("求和:"+sum+"   使用时间"+(System.currentTimeMillis()-time));
        pool.shutdown();
    }
}

ForkJoinPool-1-worker-50求和完了:10
ForkJoinPool-1-worker-8求和完了:58
ForkJoinPool-1-worker-36求和完了:26
ForkJoinPool-1-worker-58求和完了:74
ForkJoinPool-1-worker-44求和完了:90
ForkJoinPool-1-worker-22求和完了:42
ForkJoinPool-1-worker-23求和完了:106
ForkJoinPool-1-worker-37求和完了:122
ForkJoinPool-1-worker-2求和完了:138
ForkJoinPool-1-worker-52求和完了:154
ForkJoinPool-1-worker-38求和完了:170
ForkJoinPool-1-worker-24求和完了:186
ForkJoinPool-1-worker-10求和完了:202
ForkJoinPool-1-worker-60求和完了:218
ForkJoinPool-1-worker-46求和完了:234
ForkJoinPool-1-worker-18求和完了:266
ForkJoinPool-1-worker-32求和完了:250
ForkJoinPool-1-worker-4求和完了:282
ForkJoinPool-1-worker-54求和完了:298
ForkJoinPool-1-worker-40求和完了:314
ForkJoinPool-1-worker-26求和完了:330
ForkJoinPool-1-worker-41求和完了:378
ForkJoinPool-1-worker-50求和完了:394
ForkJoinPool-1-worker-48求和完了:362
ForkJoinPool-1-worker-12求和完了:346
求和:5050   使用时间232

CompletionService

Callable

并发

使用场景