Java高级知识复盘之线程通信,线程死锁,线程特性,线程状态

Java高级知识复盘之线程通信,线程死锁,线程特性,线程状态

线程死锁
线程通信
线程特性
线程状态

1 线程死锁

1.1 基础介绍

(1)线程之间出现彼此等待现象
	等待对方释放对象锁
	线程死锁  程序卡死
(2)当程序员使用synchronizedReentrantLock方式不当时,就会出现死锁现象
(3)该现象需避免	

1.2 synchronized

    /**
     * 同步锁synchronized:
     * 线程死锁解决办法:锁顺序一致 | 不要嵌套使用
     */
    private static void method2() {
        Object o1 = new Object();
        Object o2 = new Object();
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (o1) {
                    System.out.println(Thread.currentThread().getName() + "获取到o1");
                }
                synchronized (o2) {
                    System.out.println(Thread.currentThread().getName() + "获取到o2");
                }
            }
        }, "threadA");

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (o2) {
                    System.out.println(Thread.currentThread().getName() + "获取到o2");
                }
                synchronized (o1) {
                    System.out.println(Thread.currentThread().getName() + "获取到o1");

                }
            }
        }, "threadB");
        threadA.start();
        threadB.start();
    }

1.3 ReentrantLock

1.3.1
  /**
     * 显示锁ReentrantLock:
     * 线程死锁解决办法:锁顺序一致 | 不要互相嵌套
     */
    private static void method4() {
        ReentrantLock lock1 = new ReentrantLock();
        ReentrantLock lock2 = new ReentrantLock();
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                lock1.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " lock1");

                } finally {
                    lock1.unlock();
                }

                lock2.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " lock2");
                } finally {
                    lock2.unlock();
                }
            }
        }, "threadA");
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                lock1.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " lock1");

                } finally {
                    lock1.unlock();
                }

                lock2.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " lock2");
                } finally {
                    lock2.unlock();
                }
            }
        }, "threadB");
        threadA.start();
        threadB.start();
    }
1.3.2
 /**
     * 显示锁ReentrantLock:
     * 线程死锁解决办法:
     * tryLock():
     * 尝试获取锁
     * 若能获取锁,返回值为true;反之为false
     *
     * tryLock(num,TimeUnit):
     * 尝试获取锁,若不能获取锁,最多等待多久
     * 若能获取锁,返回值为true;反之为false
     */
    private static void method5() {
        ReentrantLock lock1 = new ReentrantLock();
        ReentrantLock lock2 = new ReentrantLock();
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                lock1.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " lock1");
                    /**
                     * tryLock():
                     *  尝试获取锁
                     *  若能获取锁,返回值为true;反之为false
                     *
                     *  tryLock(num,TimeUnit):
                     *  尝试获取锁,若不能获取锁,最多等待多久
                     *  若能获取锁,返回值为true;反之为false
                     */
                    if (lock2.tryLock(3, TimeUnit.SECONDS)) {
                        try {
                            System.out.println(Thread.currentThread().getName() + " lock2");
                        } finally {
                            lock2.unlock();
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock1.unlock();
                }
            }
        }, "threadA");
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                lock2.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " lock2");
                    if (lock1.tryLock(3, TimeUnit.SECONDS)) {
                        try {
                            System.out.println(Thread.currentThread().getName() + " lock1");
                        } finally {
                            lock1.unlock();
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock2.unlock();
                }
            }
        }, "threadB");
        threadA.start();
        threadB.start();
    }

2 线程通信(重要)

2.1 基础介绍

(1)线程交互
(2)内容:
	共享主存;
	生产者消费者模式  相对而言

2.2 案例

2.2.1 synchronized
package com.javasm.thread.exchange;

/**
 * @author: ShangMa
 * @className: WareHouse
 * @description: 存放任务的仓库
 * @date: 2022/8/17 10:48
 */
public class WareHouse {
    // 仓库已有任务量
    private Integer num = 0;
    // 仓库最大任务容纳量
    private final Integer MAX = 100;

    /**
     * 模拟:向仓库中存任务
     *
     * 生产任务
     */
    public void put() {
        synchronized (this) {
            while (num >= MAX) {
                // 仓库已满
                System.out.println("仓库已满,生产者线程停止");
                /**
                 * 生产者线程停止:
                 *  sleep():不主动释放对象锁,在此不合适
                 *  wait():
                 *      释放对象锁
                 *      进入线程的对象的等待池中  等待
                 *
                 *  sleep()和wait()区别?
                 *
                 *  sleep方法是Thread的静态方法,wait方法是Object的实例方法;
                 *  sleep方法可以作用在任何位置,wait方法可以作用于同步方法或同步代码块中;
                 *  sleep方法不释放对象锁,wait方法释放对象锁
                 */
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            num++;
            System.out.println(Thread.currentThread().getName() + "生产了一个任务:" + num);
            /**
             * notify():
             *  随机唤醒等待池中的某个消费者线程
             * notifyAll():
             *  唤醒生产者等待池中的所有消费者线程
             *
             */
            this.notifyAll();
        }
    }

    /**
     * 模拟:从仓库中取任务
     * <p>
     * 消费任务
     */
    public void take() {
        synchronized (this) {
            while (num <= 0) {
                System.out.println("仓库已空,消费者线程停止");
                try {
                    // 让消费者线程停止
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "消费了一个任务:" + num);
            /**
             * notify():
             *  随机唤醒等待池中的某个生产者线程
             * notifyAll():
             *  唤醒生产者等待池中的所有生产者线程
             *
             */
            // this.notify();
            this.notifyAll();
        }
    }
}
2.2.2 ReentrantLock
package com.javasm.thread.exchange;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: ShangMa
 * @className: WareHouse2
 * @description: 存放任务的仓库类
 * @date: 2022/8/17 14:51
 */
public class WareHouse2 {
    // 仓库中当前的任务量
    private Integer num = 0;
    // 仓库中可容纳的最大任务量
    private final Integer MAX = 100;

    // 显示锁
    private ReentrantLock lock1 = new ReentrantLock();
    private Condition condition = lock1.newCondition();


    /**
     * 生产任务
     * 生产者线程
     */
    public void put() {
        lock1.lock();
        try {
            while (num == MAX) {
                System.out.println("仓库已满,生产者线程停止");
                try {
                    // 让当前线程进入对象的等待池等待
                    condition.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            num++;
            System.out.println(Thread.currentThread().getName() + "生产了一个任务: " + num);
            // 唤醒消费者线程执行任务
            condition.signal();
        } finally {
            lock1.unlock();
        }
    }

    /**
     * 消费任务
     * 消费者线程
     */
    public void take() {
        lock1.lock();
        try {
            while (num == 0) {
                System.out.println("仓库已空,消费者线程停止");
                try {
                    // 让消费者线程停止
                    condition.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "消费了一个任务:" + num);
            /**
             * signal():随机唤醒等待池中的任意一个生产者线程
             * signalAll():唤醒待池中的所有生产者线程
             */
            condition.signal();
        } finally {
            lock1.unlock();
        }
    }
}

2.3 sleep方法和wait方法区别(重要)

(1)sleep方法是Thread的静态方法,wait方法是Object的实例方法;
(2)sleep方法可以作用在任何位置,wait方法可以作用于同步方法或同步代码块中;
(3)sleep方法不释放对象锁,wait方法释放对象锁

3 线程特性(重要)

3.1 基础介绍

(1)原子性:
	不可再分割
	一系列操作要么全部都执行,要么全部都不执行
	线程执行期间不被打断
	
	synchronized    锁粒度较大
	ReentrantLock   锁粒度较大 
	原子性类          锁粒度较小
(2)可见性:
	一个线程对共享主存中的值操作,被其他线程看到
	synchronized
	ReentrantLock
	volatile:
		修饰成员变量;
		保证成员变量在多线程之间的可见性;
		强制要求:
			线程每次都要从主存中获取最新值;
			当对成员变量值修改后立马将修改后的值刷新回主存
(3)有序性:
	代码的编写顺序和指令的执行顺序不一定一致
	JVM会对指令重排序->提高性能
    
    底层:
    	单线程环境下,程序结果不会受影响
    	多线程环境下,程序结果不保证
	
	volatile:禁止JVM进行指令重排序

3.2 案例

3.2.1 可见性
package com.javasm.thread.features;

import java.util.concurrent.TimeUnit;

/**
 * @author: ShangMa
 * @className: FeaturesExercise
 * @description: 线程特性
 * @date: 2022/8/17 15:13
 */
public class FeaturesExercise {
    /**
     * volatile:
     * 线程之间的可见性,不能保证线程之间的原子性
     * 修饰成员变量->保证成员变量在多线程之间的可见性
     *
     * 强制要求线程每次都要从主存中获取最新值,当对成员变量值修改后立马将修改后的值刷新回主存
     */
    private static volatile boolean isTrue = true;
    private static volatile int num = 0;

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


    /**
     * volatile:
     * 不能保证线程之间的原子性
     */
    private static void method2() {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    num++;
                }
            }
        }, "threadA");
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    num--;
                }
            }
        }, "threadB");
        threadA.start();
        threadB.start();
        try {
            threadA.join();
            threadB.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 结果不正确
        System.out.println("结果:" + num);
    }

    /**
     * volatile:
     * 保证线程之间的可见性
     */
    private static void method1() {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                while (isTrue) {//死循环

                }
            }
        }, "threadA");
        threadA.start();
        try {
            // 让主线程休眠5秒
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        isTrue = false;
        System.out.println("程序结束");
    }
}
8.2.2 有序性
3.2.2.1 饿汉模式
package com.javasm.thread.features;

/**
 * @author: ShangMa
 * @className: HungerSingleton
 * @description: 饿汉单例模式
 * @date: 2022/8/17 15:40
 */
public class HungerSingleton {
    /**
     * 饿汉单例模式:
     * 类加载时,创建对象
     * 类加载一次,创建一个对象
     */
    // 私有的静态的属性
    private static HungerSingleton singleton = new HungerSingleton();

    // 私有的构造
    private HungerSingleton() {

    }

    // 公开的静态的方法
    public static HungerSingleton getSingleton() {
        return singleton;
    }
}
3.2.2.2 懒汉模式
package com.javasm.thread.features;

/**
 * @author: ShangMa
 * @className: LazySingleton
 * @description: 懒汉单例模式
 * @date: 2022/8/17 15:33
 */
public class LazySingleton {
    // volatile:禁止指令重排序
    private volatile static LazySingleton singleton;

    private LazySingleton() {

    }

    public static LazySingleton getSingleton() {
        /**
         * 分配空间  2
         * 创建对象  5
         * 引用赋值  1
         *
         */
        // 双重检测  double check
        if (singleton == null) {
            synchronized (LazySingleton.class) {
                if (singleton == null) {
                    singleton = new LazySingleton();
                }
            }
        }
        return singleton;
    }
}

4 线程状态(重要)

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,// 新建,创建对象,但是还没被启动

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,// 可运行,启动还没被执行  等待os调度器调度

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,// 阻塞,等待对象锁(等其他线程释放对象锁) | 进入对象的等待池

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called {@code Object.wait()}
         * on an object is waiting for another thread to call
         * {@code Object.notify()} or {@code Object.notifyAll()} on
         * that object. A thread that has called {@code Thread.join()}
         * is waiting for a specified thread to terminate.
         */
        WAITING,// 等待

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,// 限时的等待

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;// 终止  正常终止 | 不正常终止(异常)
    }

5 线程池

5.1 基础介绍

(1)池化技术   复用资源,提高性能
(2)频繁创建线程、销毁线程,影响性能
(3)复用资源:
	提前在线程池准备好一些线程;
	任务提交给线程池,从线程池中挑选一个线程执行任务;
	执行任务结束,线程会再次回到线程池中,方便接下一个任务;
	当线程池关闭时,结束线程

5.2 案例

package com.javasm.thread.create;

import java.util.concurrent.*;

/**
 * @author: ShangMa
 * @className: ThreadPoolExercise
 * @description: 线程池
 * @date: 2022/8/17 16:12
 */
public class ThreadPoolExercise {
    public static void main(String[] args) {
        /*public ThreadPoolExecutor(
                int corePoolSize,核心线程数量
                int maximumPoolSize,最大线程数量
                long keepAliveTime,
                TimeUnit unit,非核心线程闲置时间
                BlockingQueue<Runnable> workQueue) {任务队列
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                    Executors.defaultThreadFactory(), defaultHandler);
        }*/

        /**
         * 当有任务提交到线程池,会先判断核心线程数量是否已达到;
         * 若未达到核心线程数量,则创建核心线程执行任务;
         * 若已达到核心线程数量,则把任务放到任务队列中;
         * 若任务队列已满,而未达到最大线程数量,则创建非核心线程执行任务;
         * 若任务队列已满,也已达到最大线程数量,则拒绝执行任务
         */
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                3,//核心线程数量
                10,//最大线程数量
                3,
                TimeUnit.SECONDS,//非核心线程闲置最大时间
                new ArrayBlockingQueue<>(4));//任务队列
        for (int i = 0; i < 100; i++) {
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"执行任务");
                }
            });
        }
    }

    private static void method1() {
        // 创建线程数量固定的线程池
        // ExecutorService service = Executors.newFixedThreadPool(2);
        // 创建只有单个线程的线程池
        // ExecutorService service = Executors.newSingleThreadExecutor();
        // 创建线程数量可伸缩的线程池
        //ExecutorService service = Executors.newCachedThreadPool();
        // 创建执行延时任务|定时任务的线程池
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
        /*service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"执行任务");
            }
        },2, TimeUnit.SECONDS);*/
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"执行任务");
            }
        },2,4,TimeUnit.SECONDS);

        // 把任务交给线程池  submit()***     execute()
        /*for (int i = 0; i < 2; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"执行任务");
                }
            });
        }*/

        // 关闭线程池
        // service.shutdown();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java开发工程师的复盘通常包括以下内容: 1. 项目回顾:回顾参与的项目,包括项目的目标、范围、进展和成果。评估项目的成功度和不足之处,总结项目经验和教训。 2. 技术复盘:回顾所使用的技术栈和工具,评估其在项目中的应用效果和可行性。探讨技术选型的优劣,总结技术上的挑战和解决方案。 3. 代码复盘:审查自己编写的代码,评估代码的质量和可维护性。检查是否符合编码规范和最佳实践,发现潜在的问题并进行改进。 4. 故障排查与修复:回顾在项目中遇到的故障和问题,分析排查过程和解决方案。总结故障处理经验,以便在未来遇到类似问题时能够更好地应对。 5. 团队合作与沟通:评估自己在团队合作中的表现,包括与其他开发人员、测试人员和项目经理的协作情况,沟通效果和问题解决能力。 6. 个人成长与学习:反思自己在项目中的技术进步和个人成长,记录学到的新知识和经验。制定个人学习计划,确定下一步的技术提升目标和学习路径。 7. 总结与改进:总结复盘过程中得出的结论和建议,提出项目和个人改进的措施。制定具体的行动计划,以便在下一次项目中能够更好地应对挑战。 复盘是一个持续学习和不断改进的过程,通过反思和总结过去的经验,可以帮助Java开发工程师不断提高自己的技术水平和工作效率,为未来的项目取得更好的成果做好准备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值