多线程简单笔记

线程
  • main函数是一个线程,JVM启动时调用,线程名字是main
  • 实现一个线程,必须创建Thread实例,重写run(),调用start();
  • JVM启动后有多个线程,只有有一个非守护线程
  • 调用start()后,至少两个线程,一个是被调用的线程,一个是调用的线程
  • 生命周期 new–>runnable–>running–>block–>terminated
创建线程
继承Thread类重写run()方法
    //匿名内部类实现
    new Thread(){
        @Override
        public void run() {
            for (int i=0;i<1000;i++){
                System.out.println("task2:" +i);
            }
        }
    }.start();
实现Runnable接口
public class ThreadRunnable implements Runnable {
    private int index = 1;
    private int max = 50;

    public void run() {
        while (index<=max){
            System.out.println(Thread.currentThread()+"index:"+(index++));
        }
    }

    public static void main(String[] args) {
        ThreadRunnable threadRunnable = new ThreadRunnable();
        Thread thread1 = new Thread(threadRunnable,"tak1");
        Thread thread2 = new Thread(threadRunnable,"tak2");
        Thread thread3 = new Thread(threadRunnable,"tak3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}


//输出结果为
Thread[tak1,5,main]index:2
Thread[tak2,5,main]index:1
Thread[tak3,5,main]index:3
Thread[tak2,5,main]index:5
Thread[tak1,5,main]index:4
Thread[tak2,5,main]index:7
Thread[tak3,5,main]index:6
Thread[tak2,5,main]index:9
Thread[tak1,5,main]index:8
Thread[tak2,5,main]index:11
Thread[tak3,5,main]index:10
Thread[tak2,5,main]index:13
Thread[tak1,5,main]index:12
Thread[tak2,5,main]index:15
Thread[tak3,5,main]index:14
Thread[tak2,5,main]index:17
Thread[tak1,5,main]index:16
Thread[tak2,5,main]index:19
Thread[tak3,5,main]index:18
Thread[tak2,5,main]index:21
Thread[tak1,5,main]index:20
Thread[tak2,5,main]index:23
Thread[tak3,5,main]index:22
Thread[tak2,5,main]index:25
Thread[tak1,5,main]index:24
Thread[tak2,5,main]index:27
Thread[tak3,5,main]index:26
Thread[tak2,5,main]index:29
Thread[tak1,5,main]index:28
Thread[tak2,5,main]index:31
Thread[tak3,5,main]index:30
Thread[tak2,5,main]index:33
Thread[tak1,5,main]index:32
Thread[tak2,5,main]index:35
Thread[tak3,5,main]index:34
Thread[tak2,5,main]index:37
Thread[tak1,5,main]index:36
Thread[tak2,5,main]index:39
Thread[tak3,5,main]index:38
Thread[tak2,5,main]index:41
Thread[tak1,5,main]index:40
Thread[tak2,5,main]index:43
Thread[tak3,5,main]index:42
Thread[tak2,5,main]index:45
Thread[tak1,5,main]index:44
Thread[tak2,5,main]index:47
Thread[tak3,5,main]index:46
Thread[tak2,5,main]index:49
Thread[tak1,5,main]index:48
Thread[tak3,5,main]index:50
构造函数
  • 创建线程对象默认线程名Thread-0从0开始递增
  • 构造线程对象时未传入ThreadGroup,则会默认获取父线程的ThreadGroup做为该线程的ThreadGroup,此时子线程和父线程在同一个ThreadGroup中
  • stacksize表示该线程占用的stack大小,默认为0,默认忽略此参数 该参数有的平台会无效
守护线程
public final void setDaemon(boolean on)
  • 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出
  • 该方法必须在启动线程前调用。
  • 该方法首先调用该线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException(在当前线程中)。
参数

on - 如果为 true,则将该线程标记为守护线程。

public class DaemonThread {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
               Thread sun = new Thread(new Runnable() {
                    public void run() {
                       for(int i =0;i<1000;i++){
                           System.out.println(Thread.currentThread().getName()+i);
                       }
                    }
                },"t2");
                 //设置守护线程  t1线程结束后 t2线程立刻终止,若不设置则t1线程done后t2线程不会结束     (只有守护线程运行时Java虚拟机退出)
               sun.setDaemon(true);
               sun.start();
                try {
                    Thread.sleep(1);
                    System.out.println(Thread.currentThread().getName()+"done!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1").start();
    }
}
基本api
  • setPriority(int newPriority) 设置优先级
  • join() 等待该线程终止。
public class ThreadApi {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(1000L);
                    for(int j=0;j<10;j++){
                        System.out.println(Thread.currentThread().getName()+"   "+j);
                    }
                    System.out.println("t1 thread done!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(1000L);
                    for(int i=0;i<10;i++){
                        System.out.println(Thread.currentThread().getName()+"   "+i);
                    }
                    System.out.println("t2 thread done!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t2");
        t1.start();
        t2.start();
        //main 线程等待t1,t2线程执行完之后再执行,但t1,t2之间轮换执行。
        t1.join();
        t2.join();

        System.out.println("main thread done");
    }
}


输出结果
t2   0
t2   1
t2   2
t2   3
t2   4
t1   0
t2   5
t1   1
t1   2
t1   3
t1   4
t2   6
t1   5
t1   6
t1   7
t1   8
t1   9
t2   7
t1 thread done!
t2   8
t2   9
t2 thread done!
main thread done

Process finished with exit code 0
  • void interrupt() 中断线程。
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
            while (true){
                try {
                    Thread.sleep(10);
                    System.out.println(1);
                } catch (InterruptedException e) {
                //捕获到异常后中断线程
                    System.out.println("打断!");
                    e.printStackTrace();
                    break; //return;
                }
            }
            }
        });
        t1.start();
        System.out.println(t1.isInterrupted());
        t1.interrupt();
        System.out.println(t1.isInterrupted());
    }

暴力中断线程
定义一个子线程,设置为守护线程,中断主线程从而中断子线程
public class ShutDownThread {
    private Thread executeThread;
    private static boolean flag = false;


    public void execute(final Runnable runnable) throws InterruptedException {
        executeThread = new Thread(){
            @Override
            public void run() {
                Thread t = new Thread(runnable);
                t.setDaemon(true);
                t.start();
                try {
                    t.join();
                } catch (InterruptedException e) {
                    flag = true;
                    e.printStackTrace();
                }
            }
        };
        executeThread.start();
    }

    public void shutdownT(long mills){
        long currentTime = System.currentTimeMillis();
        while(!flag){
            if(System.currentTimeMillis()-currentTime>=mills){
                System.out.println("超时!");
                executeThread.interrupt();
                break;
            }
            try {
                executeThread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("主线程被打断"+executeThread.getName());
                break;
            }
        }
        System.out.println("1");
        flag = false;
    }

    public static void main(String[] args)  throws Exception{
        ShutDownThread thread = new ShutDownThread();
        long begin = System.currentTimeMillis();
        thread.execute(new Runnable() {
            public void run() {
                while(true){

                }
            }
        });
        thread.shutdownT(20);
        long end = System.currentTimeMillis();
        System.out.println(end-begin);
    }
}
同步锁
  • 锁住的代码块为单线程执行
  • 默认为this锁
    private static final Object LOCK = new Object();
    
    
    public void run() {
            while (true) {
                synchronized (LOCK) {
                    if (index > max)
                        break;
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "  index:   " + (index++));
                }
            }
    }
  • 方法锁,该方法为单线程,一旦某一线程抢占到后,则该线程执行完方法内的所有内容再释放资源再进行重新抢占锁(this锁)
  • 调用this锁时,若有其他线程调用该类中的其他方法则需要等待该锁结束后才可以调用。
    public synchronized void run() {
            while (true) {
                
                    if (index > max)
                        break;
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "  index:   " + (index++));
                
            }
    }
  • 如下,t1调用m1()后锁住Test类,t2需要等待t1执行完毕后才可以调用m2()
  • t1,t3立马输出,t2等待t1结束后输出。
public class SynchronizedThis {
    public static void main(String[] args) {
        final Test t = new Test();
        new Thread(new Runnable() {
            public void run() {
                try {
                    t.m1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1").start();
        new Thread(new Runnable() {
            public void run() {
                try {
                    t.m2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t2").start();
        new Thread(new Runnable() {
            public void run() {
                try {
                    t.m3();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t3").start();
    }
}

class Test{
    public synchronized void m1() throws InterruptedException {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(10000);
    }
    public synchronized void m2() throws InterruptedException {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(10000);
    }
    public void m3() throws InterruptedException {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(10000);
    }
}
  • 静态代码块中加锁,可以让如上案例中的t3也在t1结束后再输出,t3调用m3()时需要先进入静态代码块,而t1调用m1()后会先锁住静态代码块。

  • notify(); 线程通信 唤醒一个同一个锁下wait()的线程

  • wait(); 放弃当前所拥有的锁

单生产消费模型(多生产消费时会出问题)
public class PC {
    private static int i = 0;
    private static boolean isCud = true; //是否被消费
    final static Object LOCK = new Object();

    public void product() throws InterruptedException {
        synchronized (LOCK) {
            if (isCud) {
                i++;
                System.out.println("p->" + i);
                LOCK.notify();
                isCud = false;
            } else {
                LOCK.wait();
            }
        }
    }

    public void consume() {
        synchronized (LOCK) {
            if (!isCud) {
                System.out.println("c->"+i);
                LOCK.notify();
                isCud = true;
            } else {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        final PC p = new PC();
        new Thread(){
            @Override
            public void run() {
                while(true) {
                    try {
                        p.product();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                while(true) {
                    try {
                        p.consume();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}
当有多个生产者或者消费者时,以上代码出现问题,所有线程进入wait()(假死)状态

代码修改为

  • 如下代码中,若使用if,则: 有多个生产线程被notify后,其中一个抢到了锁,生产了数据释放锁后,另一个线程则直接执行wait()后的代码(已被notif()),则会出现重复生产数据或消费数据。
public class PC {
    private static int i = 0;
    private static boolean isCud = true; //是否被消费
    final static Object LOCK = new Object();

    public void product() throws InterruptedException {
        synchronized (LOCK) {
            while(!isCud){   //不使用if  ,使用if会出现问题。
                LOCK.wait();
            }
                i++;
                System.out.println("p->" + i);
                LOCK.notifyAll();
                isCud = false;
        }
    }

    public void consume() {
        synchronized (LOCK) {
            while (isCud){
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

                System.out.println("c->"+i);
                LOCK.notifyAll();
                isCud = true;
        }
    }

    public static void main(String[] args) {
        final PC p = new PC();
        new Thread("p1"){
            @Override
            public void run() {
                while(true) {
                    try {
                        p.product();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread("p2"){
            @Override
            public void run() {
                while(true) {
                    try {
                        p.product();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread("p3"){
            @Override
            public void run() {
                while(true) {
                    try {
                        p.product();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread("c1"){
            @Override
            public void run() {
                while(true) {
                    try {
                        p.consume();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread("c2"){
            @Override
            public void run() {
                while(true) {
                    try {
                        p.consume();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread("c3"){
            @Override
            public void run() {
                while(true) {
                    try {
                        p.consume();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}
wait()和sleep()的区别
  • sleep()是Thread的方法,wait()是Object的方法
  • sleep()不会释放锁,wait()会释放锁
  • sleep()使用不需要依赖monitor,wait()需要依赖(锁对象)
  • sleep()方法不需要唤醒,wait()需要()
自定义锁的实现
接口

import java.util.Collection;
import java.util.concurrent.TimeoutException;

public interface Lock {
    void lock() throws InterruptedException;
    void lock(long mills) throws InterruptedException, TimeoutException;
    void unlock();
    Collection<Thread> getBlockThread();
    int getBlockThreadSize();
}
实现类
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;

public class BooleanLock implements Lock {
    //为false时,锁可以被获取
    // 为true说明已有线程获得锁,其他线程无法获得
    private boolean initValue;
    //正在wait()的线程
    private Set<Thread> blockThreadCollection = new HashSet<>();
    private static Thread thread; //当前拿到锁的线程

    public BooleanLock() {
        this.initValue = false;
    }

    public synchronized void lock() throws InterruptedException {
        //未拿到锁
        while(initValue){
            blockThreadCollection.add(Thread.currentThread());
            this.wait();
        }
        thread = Thread.currentThread();
        //拿到锁
        blockThreadCollection.remove(Thread.currentThread());
        System.out.println(Thread.currentThread().getName()+"拿到锁");
        this.initValue = true;
    }
    //超时锁
    public synchronized void lock(long mills) throws InterruptedException, TimeoutException {
        if(mills<=0)
            lock();
        long endTime = System.currentTimeMillis() + mills;
        long time = mills;
        while (initValue){
            if(time<=0)
                throw new TimeoutException("Time out");
            blockThreadCollection.add(Thread.currentThread());
            this.wait(mills);
            time = endTime - System.currentTimeMillis();
        }
        initValue = true;
        this.thread = Thread.currentThread();
    }

    public synchronized void unlock() {
        //只能由拿到锁的线程去释放锁
        if(thread==Thread.currentThread()){
            this.initValue = false;
            System.out.println(Thread.currentThread().getName()+"已释放掉锁!");
            this.notifyAll();
        }
    }

    public Collection<Thread> getBlockThread() {
        //不能修改这个collection对象
        return Collections.unmodifiableCollection(blockThreadCollection);
    }

    public int getBlockThreadSize() {
        return blockThreadCollection.size();
    }
//测试超时锁
    public static void main(String[] args) {
        BooleanLock lock = new BooleanLock();
        Stream.of("t1","t2").forEach(name->{
            new Thread(()->{
                try {
                    lock.lock(10_000);
                    System.out.println(lock.getBlockThread());
                    lock.test();
                } catch (InterruptedException | TimeoutException e) {
                    System.out.println(Thread.currentThread().getName()+"已超时");
                    System.out.println(lock.getBlockThread());
                }finally {
                    lock.unlock();
                }
            },name).start();
        });
    }

    public void test(){
        System.out.println(Thread.currentThread().getName()+"  working");
        try {
            Thread.sleep(30_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
//测试锁方法
class TestLock{
    public static void main(String[] args) {
        final BooleanLock booleanLock = new BooleanLock();
        Stream.of("t1","t2","t3","t4").forEach(name->
                new Thread(()->{
                    try {
                        booleanLock.lock();
                        System.out.println(Thread.currentThread().getName()+" have the lock");
                        System.out.println(booleanLock.getBlockThread());
                        work();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        booleanLock.unlock();
                    }
                },name).start());
    }

    public static  void work(){
        System.out.println(Thread.currentThread().getName()+" is working...");
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
线程组
线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。
允许线程访问有关自己的线程组的信息,但是不允许它访问有关其线程组的父线程组或其他任何线程组的信息。
  • ThreadGroup(String name) 构造一个新线程组。
  • ThreadGroup(ThreadGroup parent, String name) 创建一个新线程组。
测试
public class ThreadGroupTest {
    public static void main(String[] args) {
        ThreadGroup group = new ThreadGroup("tg1");
        ThreadGroup group1 = new ThreadGroup(group,"tg2");
        new Thread(group1,"t1"){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getThreadGroup().getName());
                System.out.println(Thread.currentThread().getThreadGroup().getParent().getName());
            }
        }.start();
    }
}
简单实现线程池
import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;

public class SimpleThreadPool {

    private final int queueSize;        // 任务队列长度限制
    private final int size;                     //要开启的线程数
    private final static int DEFAUlT_SIZE = 10;   //默认线程数
    private static volatile int seq = 0;
    private final static LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();     //task queue
    private final static ThreadGroup GROUP = new ThreadGroup("Pool_Group");  // default threadgroup
    private final static String THREAD_PREFIX = "SIMPLE_THREAD_POLL-";                //thread prefix
    private final static List<WorkerTask> THREAD_QUEUE = new LinkedList<>();         //thread  queue
    private final static int DEFAUT_TASK_QUEUE_SIZE = 2000;  //默认任务队列长度
    private final DiscardPolicy discardPolicy;
    private volatile boolean destroy = false;     //线程池的存活状态
    //默认拒绝策略
    public final static DiscardPolicy DEFAUT_DISCARD = () -> {
        throw new DiscardException("This task is discarded!");
    };


    public SimpleThreadPool(int size, int queueSize, DiscardPolicy discardPolicy) {
        this.size = size;
        this.queueSize = queueSize;
        this.discardPolicy = discardPolicy;
        init();
    }

    public SimpleThreadPool() {
        this(DEFAUlT_SIZE, DEFAUT_TASK_QUEUE_SIZE, DEFAUT_DISCARD);
    }

    //初始化
    private void init() {
        for (int i = 0; i < size; i++) {
            createWorkerTask();
        }

    }

    private void createWorkerTask() {
        WorkerTask workerTask = new WorkerTask(GROUP, THREAD_PREFIX + (seq++));
        workerTask.start();
        THREAD_QUEUE.add(workerTask);
    }

    public boolean destroy(){
        return this.destroy;
    }


    //提交任务
    public void submit(Runnable runnable) {
        if(destroy){      //线程池已销毁
            throw new IllegalStateException("thread pool already close!");
        }
        synchronized (TASK_QUEUE) {
            if (TASK_QUEUE.size() >= queueSize)
                discardPolicy.discard();
            TASK_QUEUE.addLast(runnable);
            TASK_QUEUE.notifyAll();         //通知所有等待的队列
        }
    }

    //关闭线程池
    public void shutdown() throws InterruptedException{
        while(!TASK_QUEUE.isEmpty()){    //任务队列不为空
            Thread.sleep(50);   //等待
        }
        int initVal = THREAD_QUEUE.size();
        while(initVal>0){
            for(WorkerTask task:THREAD_QUEUE){
                if(task.getTaskState()==TaskState.BLOCK){          //是否有等待状态的队列
                    task.interrupt();   //打断当前BLOCKED的线程
                    task.close();   //设置状态为DEAD
                    initVal--;
                }else{
                 Thread.sleep(10);    //等待执行
                }
            }
        }
        this.destroy = true;          // 全部关闭后设置销程池的销毁状态
        System.out.println("Thread pool disposed!");
    }


    //线程状态
    private enum TaskState {
        FREE, RUNNING, BLOCK, DEAD
    }

    //拒绝策略抛出异常
    public static class DiscardException extends RuntimeException {
        public DiscardException(String message) {
            super(message);
        }
    }

    //拒绝策略
    public interface DiscardPolicy {
        void discard() throws DiscardException;
    }

    private static class WorkerTask extends Thread {
        private volatile TaskState taskState = TaskState.FREE;

        public TaskState getTaskState() {
            return taskState;
        }

        public WorkerTask(ThreadGroup group, String name) {
            super(group, name);
        }

        public void close() {
            this.taskState = TaskState.DEAD;
        }

        @Override
        public void run() {
            OUTER:
            while (this.taskState != TaskState.DEAD) {
                Runnable runnable;
                synchronized (TASK_QUEUE) {
                    while (TASK_QUEUE.isEmpty()) {
                        try {
                            taskState = TaskState.BLOCK;
                            TASK_QUEUE.wait();
                        } catch (InterruptedException e) {
                            break OUTER;   //线程被打断后跳转的位置
                        }
                    }
                    //todo
                    runnable = TASK_QUEUE.removeFirst();  //获取到第一个任务
                }
                if (runnable != null) {
                    taskState = TaskState.RUNNING;
                    runnable.run();    //执行任务
                    taskState = TaskState.FREE;
                }

            }
        }
    }


    public static void main(String[] args) {
       // SimpleThreadPool simpleThreadPool = new SimpleThreadPool(10, 10, SimpleThreadPool.DEFAUT_DISCARD);  //测试拒绝策略
        SimpleThreadPool simpleThreadPool = new SimpleThreadPool();
        IntStream.rangeClosed(0, 40).forEach(i -> {
            simpleThreadPool.submit(() -> {
                System.out.println("Thread " + i + " RunTime in " + Thread.currentThread().getName() + " begin");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread  " + i + "  RunTime in  " + Thread.currentThread().getName() + "  finished.");
            });
        });
        try {
            Thread.sleep(1000);
            simpleThreadPool.shutdown();
            simpleThreadPool.submit(()->{
                System.out.println("1");
            });
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值