美文网首页
JAVA-线程知识点补充

JAVA-线程知识点补充

作者: 超人TIGA | 来源:发表于2021-03-12 22:19 被阅读0次
    线程的新启方式有几种?

    ①继承Thread类
    ②实现Runnable接口
    没有其他了,就算是实现callable接口,也是需要再包装成FutureTask,而FutureTask其实也只是实现了Runnable接口的而已。

    线程状态
    image.png 1、中间的运行态,分2种情况,分别是running和ready,其实就是CPU调度,如果CPU正在执行该线程,就是running,被剥夺或者等待就是ready。
    2、在并发编程的时候,我们可能会调用线程的wait、join、notify、notifyAll等一系列方法,进行线程间的暂停和唤醒继续执行,达到并发的效果。
    3、如果在wait、sleep等方法参数中填写时间,那就是超时的限制,避免线程无限等待。
    4、阻塞状态,其实就是锁的获取。
    注意:进入阻塞状态的情况,只有使用的是synchronize修饰符才会进入,如果使用的是显示锁,就不会了,只会进行等待。
    死锁

    达成死锁的条件:
    1、有多个线程(T>=2),同时有多个资源(S>=2),同时资源要小于线程的数量(S<=T)
    2、各个线程获取资源的顺序不一样
    3、得到某个资源后,不再释放
    举个例子就是:有2个小朋友A和B,同时又有一台游戏机和一包零食,A和B都想一边玩游戏一边吃零食;但是A优先选游戏,B优先选零食;各自得到一样之后,都想得到对方的,同时还不肯把自己已获得的给对方。这样的结果就是谁也无法既吃零食又玩游戏了。
    那如何打破死锁?
    其实主要是针对第2、3点,因为第1点基本都是跟业务有关,很多时候我们都不能主动改变。打破第2点很简单,调整获取资源的顺序就可以了,保证全部线程申请资源的顺序都一致。
    要打破第3点,就需要用Lock接口来自己实现锁了,因为Lock提供了很多方法,使得我们可以对锁进行尝试获取、释放等操作。

    /**
     *类说明:演示尝试拿锁解决死锁
     */
    public class TryLock {
        private static Lock No13 = new ReentrantLock();//第一个锁
        private static Lock No14 = new ReentrantLock();//第二个锁
    
        //先尝试拿No13 锁,再尝试拿No14锁,No14锁没拿到,连同No13 锁一起释放掉
        private static void fisrtToSecond() throws InterruptedException {
            String threadName = Thread.currentThread().getName();
            Random r = new Random();
            while(true){
                if(No13.tryLock()){
                    System.out.println(threadName
                            +" get 13");
                    try{
                        if(No14.tryLock()){
                            try{
                                System.out.println(threadName
                                        +" get 14");
                                System.out.println("fisrtToSecond do work------------");
                                break;
                            }finally{
                                No14.unlock();
                            }
                        }
                    }finally {
                        No13.unlock();
                    }
    
                }
                Thread.sleep(r.nextInt(3));
            }
        }
    
        //先尝试拿No14锁,再尝试拿No13锁,No13锁没拿到,连同No14锁一起释放掉
        private static void SecondToFisrt() throws InterruptedException {
            String threadName = Thread.currentThread().getName();
            Random r = new Random();
            while(true){
                if(No14.tryLock()){
                    System.out.println(threadName
                            +" get 14");
                    try{
                        if(No13.tryLock()){
                            try{
                                System.out.println(threadName
                                        +" get 13");
                                System.out.println("SecondToFisrt do work------------");
                                break;
                            }finally{
                                No13.unlock();
                            }
                        }
                    }finally {
                        No14.unlock();
                    }
    
                }
                Thread.sleep(r.nextInt(3));
            }
        }
    
        private static class TestThread extends Thread{
    
            private String name;
    
            public TestThread(String name) {
                this.name = name;
            }
    
            public void run(){
                Thread.currentThread().setName(name);
                try {
                    SecondToFisrt();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            Thread.currentThread().setName("TestDeadLock");
            TestThread testThread = new TestThread("SubTestThread");
            testThread.start();
            try {
                fisrtToSecond();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    活锁

    活锁是啥?其实就是解决了上面的2或者3的死锁问题,但是也有几率资源被锁住,或者最终获取到资源的时间被拉长。例如:
    线程A、B 资源锁1、2
    A得1等2->全释放->A得1等2->全释放->A得1等2
    B得2等1->全释放->B得2等1->全释放->B得2等1
    这样下去就会没完没了了,解决方法就是,可以等一等,所以上面的代码中,稍微加入了Thread.sleep(r.nextInt(3));使得线程获得锁的时间点错开,提高资源锁的获得率,也就避免了活锁了。

    ThreadLocal

    线程本地变量,让每个线程都拥有一份自己的变量副本,实现线程间的数据隔离。


    image.png

    结构就是上图那样:
    ①每个线程,都会有一个ThreadLocalMap类型的变量,threadLocals
    ②在ThreadLocalMap类里面,有一个Entry[]类型的变量,table
    ③Entry类里面,存放的是键值对,key就是ThreadLocal类型,value就是object类型。

    所以,每当在线程里面调用threadLocal的set方法时,首先会创建一个threadLocalMap的对象实例和一个Entry[]的空数组对象;然后以线程为key,把我们需要存储的值放到value里面。

    相关文章

      网友评论

          本文标题:JAVA-线程知识点补充

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