第一章、并发编程线程基础

165 阅读1分钟

本章主要是介绍线程的创建与使用,以及一些常用的方法介绍与代码示例,有助于理解。这里主要针对一些常用方法的介绍。

一、等待线程执行终止的 Join方法

public class JoinDemo {

    public static void main(String[] args) throws InterruptedException{
        Thread thread0 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread-1  over");
            }
        });

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread-2  over");
            }
        });

        thread0.start();
        thread1.start();
        System.out.println("all child thread over");

        thread0.join();
        thread1.join();
    }
}

二、让线程睡眠的sleep方法

public class SleepDemo {
    private static final Lock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException{
        // 验证 调用sleep方法 执行时睡眠线程不会释放持有的锁,直到睡眠结束执行完毕
        Thread thread0 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println("thread-1  is in sleep");
                    Thread.sleep(10000);
                    System.out.println("thread-1 is awaked");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println("thread-2  is in sleep");
                    Thread.sleep(10000);
                    System.out.println("thread-2 is awaked");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });

        thread0.start();
        thread1.start();
    }

    static class innerOne{
        // 验证 子线程执行sleep方法 在睡眠期间,主线程中断了它,子线程抛出InterruptedException,
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("thread 子线程 睡了");
                        Thread.sleep(10000);
                        System.out.println("thread 子线程 醒了");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        }
    }
}

三、让出CPU执行权的 yield方法

/**
 * yield 让出cpu使用权,线程调度器可以理会也可以忽略
 * 当调度器接收让出权后,时间片轮转到下一个,下一个线程可能是 非让出使用权的线程,也可以是让出使用权的线程
 */

public class YieldDemo implements Runnable{

    public YieldDemo() {
        Thread t = new Thread(this::run);
        t.start();
    }

    @Override
    public void run() {
        for (int i=0; i<5; i++){
            if (i%5 == 0){
                System.out.println(Thread.currentThread() + "yield cpu...");
                Thread.yield();
            }
        }
        System.out.println(Thread.currentThread() + "is over");
    }

    public static void main(String[] args) {
        new YieldDemo();
        new YieldDemo();
        new YieldDemo();
    }
}

四、线程中断

通过设置线程的中断标志 并不能直接终止该线程的执行,而是被中断的线程根据中断状态自行处理

例如 有线程A、线程B 两个线程,当线程A运行时,线程B 可以调用线程A 的Interrupt方法来设置线程A 的中断标志,这里仅仅是设置标志,线程A 并没有被中断,还会继续执行如果线程A 因为调用了 wait函数、join方法或sleep方法而被阻塞挂起,这时调用线程A 的interrupt方法 线程A 会在调用这些方法的地方抛出InterruptedException异常而返回。

public class InterruptDemo {
    /**
     * 线程使用Interrupted优雅退出的例子
     *
     * public void run(){
     *     try{
     *         //to do something...
     *         //线程退出条件
     *         while(!Thread.currentThread().isInterrupted() && more work to do){
     *             // do something
     *         }
     *     }catch(InterruptedException e){
     *         // 线程在 sleep 或者 wait 时被中断
     *     }finally{
     *         // 如果需要 cleanup
     *     }
     * }
     */
    public static void main(String[] args) throws InterruptedException {
        // 根据中断标志判断线程是否终止
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 如果当前线程中断则退出循环
                while (!Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread() + "hello!");
                }
            }
        });
        // 启动子线程
        thread.start();
        // 让主线程睡眠1S ,以便中断前让子线程输出
        Thread.sleep(1000);
        // 中断子线程
        System.out.println("子线程 中断---");
        thread.interrupt();
        //等待子线程输出
        thread.join();
        System.out.println("main thread is over---");
    }

    static class innerOne{
        // 当线程调用sleep wait join等阻塞挂起时调用 interrupt方法
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(20000000);
                        System.out.println("thread is awaked");
                    } catch (InterruptedException e) {
                        System.out.println("thread is interrupted while sleeping");
                        return;
                    }
                    System.out.println("thread-leaving normally");
                }
            });

            thread.start();
            Thread.sleep(1000);
            thread.interrupt();
            thread.join();
            System.out.println("main thread is over");
        }
    }

    static class innorTwo{
        // 通过例子了解 interrupted() 和 isInterrupted() 方法区别
        /**
         *  在interrupted()方法内部是获取当前线程的中断状态,
         *  这里虽然调用了thread的interrupted()方法,但是获取的是主线程的中断标志,因为主线程是当前线程
         */
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (;;){
                    }
                }
            });
            // 启动线程
            thread.start();
            // 设置中断标志
            thread.interrupt();
            // 获取中断标志
            System.out.println("isInterrupted:" + thread.isInterrupted());
            // 获取中断标志并重置
            System.out.println("interrupted:" + thread.interrupted());
            // 获取中断标志并重置
            System.out.println("interrupted:" + Thread.interrupted());
            // 获取中断标志
            System.out.println("isInterrupted:" + thread.isInterrupted());
            thread.join();
            System.out.println("main thread is over");
        }
    }
}

五、线程死锁

public class DeadLockDemo {
    // 死锁 样例
    private static Object resourceA = new Object();
    private static Object resourceB = new Object();

    public static void main(String[] args) {
        Thread thread0 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(resourceA){
                    System.out.println(Thread.currentThread() + "get resourceA");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting resourceB");
                    synchronized (resourceB){
                        System.out.println(Thread.currentThread() + "get resourceB");
                    }
                }
            }
        });

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceB){
                    System.out.println(Thread.currentThread() + "get resourceB");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting resourceA");
                    synchronized (resourceA){
                        System.out.println(Thread.currentThread() + "get resourceA");
                    }
                }
            }
        });

        thread0.start();
        thread1.start();
    }

    static class innorOne{
        // 修改申请资源的有序性,避免死锁发生
        public static void main(String[] args) {
            Thread thread0 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized(resourceA){
                        System.out.println(Thread.currentThread() + "get resourceA");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread() + "waiting resourceB");
                        synchronized (resourceB){
                            System.out.println(Thread.currentThread() + "get resourceB");
                        }
                    }
                }
            });

            Thread thread1 = new Thread(new Runnable() {
                // 修改 该线程的申请资源顺序
                @Override
                public void run() {
                    synchronized (resourceA){
                        System.out.println(Thread.currentThread() + "get resourceA");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread() + "waiting resourceB");
                        synchronized (resourceB){
                            System.out.println(Thread.currentThread() + "get resourceB");
                        }
                    }
                }
            });

            thread0.start();
            thread1.start();
        }
    }
}

六、ThreadLocal

/**
 * 同步的方式:加锁、ThreadLocal
 * ThreadLocal 由JDK包提供
 */
public class ThreadLocalDemo {
    // 使用示例
    private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void print(String str){
        // 打印 当前线程的本地内存中 threadLocal变量的值
        System.out.println(str + ":" + threadLocal.get());
        // 移除 当前线程本地内存中 threadLocal变量的值
        threadLocal.remove();
    }

    public static void main(String[] args) {
        Thread thread0 = new Thread(new Runnable() {
            @Override
            public void run() {
                threadLocal.set("thread-1 local variable");
                print("thread-1");
                System.out.println("线程一 移除后:" + threadLocal.get());
            }
        });

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                threadLocal.set("thread-2 local variable");
                print("thread-2");
                System.out.println("线程二 移除后:" + threadLocal.get());
            }
        });

        thread0.start();
        thread1.start();
    }

    static class innorOne{
        /**
         * ThreadLocal 不支持继承
         * 同一个ThreadLocal变量在主线程设置后,在子线程中获取不到
         */
        public static ThreadLocal<String> threadLocal = new ThreadLocal<>();

        public static void main(String[] args) {
            threadLocal.set("hello world");

            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("threadLocal:" + threadLocal.get());
                }
            });
            thread.start();
            System.out.println("main:" + threadLocal.get());
        }

    }

    static class innorTwo{
        /**
         * InheritableThreadLocal 继承自ThreadLocal
         * 提供一个特性,让子线程可以访问父线程中设置的本地变量
         */
        public static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();

        public static void main(String[] args) {
            threadLocal.set("hello world");

            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("threadLocal:" + threadLocal.get());
                }
            });
            thread.start();
            System.out.println("main:" + threadLocal.get());
        }
    }
}