美文网首页
多线程问题总结

多线程问题总结

作者: 定金喜 | 来源:发表于2020-02-04 17:16 被阅读0次

1.实现多线程的方式

a.实现Runnable接口

package com.dxc;

/**
 * @Author: ding
 * @Date: 2020-01-28 15:56
 */
public class RunnableTest implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        RunnableTest threadTest = new RunnableTest();
        for(int i=0;i<10; i++) {
            Thread thread = new Thread(threadTest);
            thread.start();
        }
    }
}

输出:

Thread-0
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-7
Thread-8
Thread-9

b.继承Thread类

package com.dxc;

/**
 * @Author: ding
 * @Date: 2020-01-28 16:18
 */
public class ThreadTest extends Thread{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
    public static void main(String[] args) {
        for(int i=0; i<10; i++) {
            ThreadTest threadTest = new ThreadTest();
            threadTest.start();
        }
    }
}

输出:

Thread-0
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-7
Thread-8
Thread-9

c.实现Callable接口

package com.dxc;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * @Author: ding
 * @Date: 2020-01-28 16:39
 */
public class CallableTest implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        Integer total = 0;
        for(int i=1; i<=100; i++) {
            total += i;
        }
        return total;
    }

    public static void main(String[] args) throws Exception{

        CallableTest callableTest = new CallableTest();
        FutureTask<Integer> futureTask = new FutureTask(callableTest);
        for (int i=0; i<10; i++) {
            Thread thread = new Thread(futureTask);
            thread.start();
        }
    }
}

2.线程状态以及相互转换

线程流转状态图1
线程流转状态图2
线程流转状态图3

New:新建状态,Thread thread = new Thread()
Runnable:可执行状态,执行thread.start()后;
Running:正在执行线程代码段
Blocked:阻塞状态,执行到Synchronized代码段时,竞争同步锁
Waiting:执行wait,join,park和await后
Time_waiting:执行带超时时间的sleep,wait,join,park和await函数
Terminated:执行结束

3.jstack线程堆栈中的状态有哪些

例子:

package com.dxc;
/**
 * @Author: ding
 * @Date: 2020-01-28 16:18
 */
public class ThreadTest extends Thread{
    /**
     * 0 time_waiting
     * 1 running
     * 2 waiting
     */
    private Integer type;
    private SubThread subThread;

    @Override
    public synchronized void  run(){
        switch (type){
            case 0:
                try {
                    Thread.sleep(60000);
                } catch (Exception ex) {

                }
                break;
            case 1:
                while (true){
                    for(int i=0; i < 1000000000000000L; i++) {
                        for(int j=0; j < 10000000000L; j++) {
                            System.out.println("111");
                        }
                    }
                }
            case 2:
                waiting();
                break;
            case 3:
                subThread.blockTest();
                break;
        }
    }

    public static class SubThread {
        public synchronized void blockTest() {
            try {
                Thread.sleep(60000);
            } catch (Exception ex) {

            }
        }
    }

    public synchronized void waiting() {
        try {
            wait();
        }catch (Exception ex){
        }
    }

    public static void main(String[] args) {

        ThreadTest thread1 = new ThreadTest();
        thread1.setName("xiancheng1");
        thread1.type = 0;
        thread1.start();

        ThreadTest thread2 = new ThreadTest();
        thread2.setName("xiancheng2");
        thread2.type = 1;
        thread2.start();

        ThreadTest thread3 = new ThreadTest();
        thread3.setName("xiancheng3");
        thread3.type = 2;
        thread3.start();

        SubThread subThread = new SubThread();

        ThreadTest thread4 = new ThreadTest();
        thread4.subThread = subThread;
        thread4.setName("xiancheng4");
        thread4.type = 3;
        thread4.start();

        ThreadTest thread5 = new ThreadTest();
        thread5.subThread = subThread;
        thread5.setName("xiancheng5");
        thread5.type = 3;
        thread5.start();
    }
}

执行jstack的结果:

"Attach Listener" #17 daemon prio=9 os_prio=31 tid=0x00007f85c6405800 nid=0x5c03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" #16 prio=5 os_prio=31 tid=0x00007f85c501a000 nid=0x2503 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"xiancheng5" #15 prio=5 os_prio=31 tid=0x00007f85c3014000 nid=0x5b03 waiting for monitor entry [0x00007000032c4000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.dxc.ThreadTest$SubThread.blockTest(ThreadTest.java:49)
    - waiting to lock <0x000000076f4808a0> (a com.dxc.ThreadTest$SubThread)
    at com.dxc.ThreadTest.run(ThreadTest.java:40)
    - locked <0x000000076f480720> (a com.dxc.ThreadTest)

"xiancheng4" #14 prio=5 os_prio=31 tid=0x00007f85c681e000 nid=0xa603 waiting on condition [0x00007000031c1000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at com.dxc.ThreadTest$SubThread.blockTest(ThreadTest.java:49)
    - locked <0x000000076f4808a0> (a com.dxc.ThreadTest$SubThread)
    at com.dxc.ThreadTest.run(ThreadTest.java:40)
    - locked <0x000000076f488588> (a com.dxc.ThreadTest)

"xiancheng3" #13 prio=5 os_prio=31 tid=0x00007f85c5019000 nid=0xa703 in Object.wait() [0x00007000030be000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076f498000> (a com.dxc.ThreadTest)
    at java.lang.Object.wait(Object.java:502)
    at com.dxc.ThreadTest.waiting(ThreadTest.java:58)
    - locked <0x000000076f498000> (a com.dxc.ThreadTest)
    at com.dxc.ThreadTest.run(ThreadTest.java:37)
    - locked <0x000000076f498000> (a com.dxc.ThreadTest)

"xiancheng2" #12 prio=5 os_prio=31 tid=0x00007f85c5010000 nid=0x5703 runnable [0x0000700002fbb000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:326)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    - locked <0x000000076f4d1a30> (a java.io.BufferedOutputStream)
    at java.io.PrintStream.write(PrintStream.java:482)
    - locked <0x000000076f484ab0> (a java.io.PrintStream)
    at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
    at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
    - locked <0x000000076f484a70> (a java.io.OutputStreamWriter)
    at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
    at java.io.PrintStream.newLine(PrintStream.java:546)
    - eliminated <0x000000076f484ab0> (a java.io.PrintStream)
    at java.io.PrintStream.println(PrintStream.java:807)
    - locked <0x000000076f484ab0> (a java.io.PrintStream)
    at com.dxc.ThreadTest.run(ThreadTest.java:32)
    - locked <0x000000076f4808b0> (a com.dxc.ThreadTest)

"xiancheng1" #11 prio=5 os_prio=31 tid=0x00007f85c3013000 nid=0xa903 waiting on condition [0x0000700002eb8000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at com.dxc.ThreadTest.run(ThreadTest.java:23)
    - locked <0x000000076f490178> (a com.dxc.ThreadTest)

"Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007f85c483a000 nid=0x4003 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007f85c580a800 nid=0x4103 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007f85c580a000 nid=0x4203 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007f85c5809000 nid=0x3c03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007f85c63ff800 nid=0x3b03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007f85c63fe800 nid=0x4503 runnable [0x00007000027a3000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:171)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    - locked <0x000000076f48ecd8> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    - locked <0x000000076f48ecd8> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007f85c4826800 nid=0x3903 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007f85c380b000 nid=0x4c03 in Object.wait() [0x000070000259d000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076f498180> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
    - locked <0x000000076f498180> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007f85c3003800 nid=0x4e03 in Object.wait() [0x000070000249a000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076f490a68> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x000000076f490a68> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
.......

主要状态有:
WAITING,TIME_WAITING,RUNNABLE,BLOCKED 。

4.线程池

参考:https://baijiahao.baidu.com/s?id=1637828094805085849&wfr=spider&for=pc
a.线程池主要参数
1.corePoolSize:核心线程数
核心线程会一直存活,即使没有任务要执行
当线程数小于核心线程数,即使有线程空闲,线程池也会优先创建新线程处理
如果设置allowCoreThreadTimeout=true(默认false),核心线程池也会超时关闭,核心线程数会变为0
2.queueCapacity:任务队列容量(阻塞)
当核心线程数达到最大时,新任务会放在任务队列中排队消费执行
3.keepAliveTime:线程空闲时间
当线程空闲时间超过keepAliveTime就释放线程,一直到线程数量=corePoolSize
如果allowCoreThreadTimeout=true,则会直到线程数量=0
4.allowCoreThreadTimeout:是否允许核心线程超时
true:允许核心线程池超时,任务执行完后,线程数量会变为0
false:不允许核心线程池超时,任务执行完后,线程数量不会变为0(核心线程数量>0前提)
5.maxPoolSize:最大线程数量
当线程数>=corePoolSize,且任务队列已满时,线程池会创建新线程来处理任务;
当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
6.rejectedExecutionHandler:任务拒绝处理器
两种情况会拒绝处理任务:(1)当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务。(2)当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务。线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常。
b.线程池拒绝策略
(1)AbortPolicy 丢弃任务,抛出RejectedExecutionException异常
(2)DiscardPolicy 丢弃任务,不抛出异常
(3)DiscardOldestPolicy 丢弃任务队列中最先入队的任务
(4)CallerRunsPolicy 执行任务
c.线程池的执行过程
1.当线程数小于核心线程数时,创建新线程;
2.当线程数大于或者等于核心线程数,且任务队列未满时,将任务放进任务队列待执行;
3.当线程数大于或者等于核心线程数,且任务队列已满。(1)若线程数小于最大线程数,创建新线程;(2)若线程数大于或者等于最大线程数时,根据拒绝策略进行处理
d.线程执行过程中失败的处理方式
先看ThreadPoolExecutor源码

线程池代码片段1
当task.run() 也就是执行线程任务出现异常时,直接捕获然后抛出,此时按照提交线程的方式,会有两种不同的情况:
(1)调用execute方法提交:
线程池代码片段2
未对command做任何封装,所以线程执行发生异常,会导致runWorker函数跳出while循环,completedAbruptly为true,然后看processWorkerExit函数,此函数的处理逻辑:
线程池代码片段3
代码段逻辑是删除掉异常的线程,并重新创建线程放入线程池。
(2)调用submit方法提交:
线程池代码片段4
会对task进行封装,看封装函数newTaskFor,最终进入到FutureTask类,看其run函数:
线程池代码片段5
这里对线程的异常进行了捕获,但是未抛出,所以这种提交方式线程不会抛出异常,callable其实跟踪源码可以看到使用了适配器模式,将Runnable接口的run方法适配到Callable接口的call方法,适配器类如下所示:
线程池代码片段6

相关文章

网友评论

      本文标题:多线程问题总结

      本文链接:https://www.haomeiwen.com/subject/kzxmthtx.html