侧边栏壁纸
博主头像
高大北博主等级

所有的再见中,我最喜欢明天见

  • 累计撰写 208 篇文章
  • 累计创建 151 个标签
  • 累计收到 20 条评论
标签搜索

目 录CONTENT

文章目录

多线程快速入门与多线程与线程高级(多线程实战【三】)

高大北
2022-05-23 / 0 评论 / 1 点赞 / 314 阅读 / 2,315 字 / 正在检测是否收录...

多线程七种执行的状态

初始化状态
就绪状态
运行状态
死亡状态
阻塞状态
超时等待
等待状态

start():调用start()方法会使得该线程开始执行,正确启动线程的方式。
wait():调用wait()方法,进入等待状态,释放资源,让出CPU。需要在同步快中调用。
sleep():调用sleep()方法,进入超时等待,不释放资源,让出CPU
stop():调用sleep()方法,线程停止,线程不安全,不释放锁导致死锁,过时。
join():调用sleep()方法,线程是同步,它可以使得线程之间的并行执行变为串行执行。
yield():暂停当前正在执行的线程对象,并执行其他线程,让出CPU资源可能立刻获得资源执行。
yield()的目的是让相同优先级的线程之间能适当的轮转执行
notify():在锁池随机唤醒一个线程。需要在同步快中调用。
nnotifyAll():唤醒锁池里所有的线程。需要在同步快中调用。

Sleep 主动释放cpu执行权 休眠一段时间
运行状态→限时等待状态
限时等待状态→就绪状态→运行状态

Synchronized 没有获取到锁 当前线程变为阻塞状态
如果有线程释放了锁,唤醒正在阻塞没有获取到锁的线程
从新进入到获取锁的状态

wait() 运行—等待状态

notify() 等待状态–阻塞状态(没有获取到锁的线程 队列)
—就绪状态→运行状态
1653272504424

sleep防止CPU占用100%

sleep(long millis) 线程睡眠 millis 毫秒
sleep(long millis, int nanos) 线程睡眠 millis 毫秒 + nanos 纳秒
使用sleep方法避免cpu空转 防止cpu占用100%

public static void main(String[] args) {
    new Thread(() -> {
        while (true) {
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

守护线程与用户线程
java中线程分为两种类型:用户线程和守护线程。通过Thread.setDaemon(false)设置为用户线程;通过Thread.setDaemon(true)设置为守护线程。如果不设置次属性,默认为用户线程。

1.守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。
2.用户线程是独立存在的,不会因为其他用户线程退出而退出。

public class Thread01 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + “,我是子线程”);
} catch (Exception e) {

            }
        }
    });
    /**
     * 1.setDaemon 设置为true 守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。
     * 2.setDaemon 设置为false 用户线程是独立存在的,不会因为其他用户线程退出而退出。
     */
    thread.setDaemon(true);
    thread.start();
    System.out.println("我是主线程,代码执行结束");
    }
}

守护线程与用户线程

java中线程分为两种类型:用户线程和守护线程。通过Thread.setDaemon(false)设置为用户线程;通过Thread.setDaemon(true)设置为守护线程。如果不设置次属性,默认为用户线程。

1.守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。
2.用户线程是独立存在的,不会因为其他用户线程退出而退出。

public class Thread01 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + ",我是子线程");
                } catch (Exception e) {

                }
            }
        });
        /**
         * 1.setDaemon 设置为true 守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。
         * 2.setDaemon 设置为false 用户线程是独立存在的,不会因为其他用户线程退出而退出。
         */
        thread.setDaemon(true);
        thread.start();
        System.out.println("我是主线程,代码执行结束");
    }
}

如何安全的停止一个线程

调用stop方法

Stop:中止线程,并且清除监控器锁的信息,但是可能导致 线程安全问题,JDK不建议用。 Destroy: JDK未实现该方法。

Interrupt(线程中止)

Interrupt 打断正在运行或者正在阻塞的线程。
1.如果目标线程在调用Object class的wait()、wait(long)或wait(long, int)方法、join()、join(long, int)或sleep(long, int)方法时被阻塞,那么Interrupt会生效,该线程的中断状态将被清除,抛出InterruptedException异常。
2.如果目标线程是被I/O或者NIO中的Channel所阻塞,同样,I/O操作会被中断或者返回特殊异常值。达到终止线程的目的。
如果以上条件都不满足,则会设置此线程的中断状态。

打断正在阻塞的线程

public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(5000);
        } catch (Exception e) {
              e.printStackTrace();
        }
    }, "t1");
    t1.start();
    try {
        Thread.sleep(1000);
    } catch (Exception e) {

    }
    System.out.println("打断子线程");
    //调用interrupt 打断正在阻塞的线程
    t1.interrupt();
    System.out.println("获取打断标记:" + t1.isInterrupted());
}

打断正在运行的线程

public class Thread06 extends Thread {
    @Override
    public void run() {
        while (true) {
            // 如果终止了线程,则停止当前线程
            if (this.isInterrupted()) {
                break;
            }
        }
    }

    public static void main(String[] args) {
        Thread06 thread06 = new Thread06();
        thread06.start();
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
        }
        thread06.interrupt();

    }
}

Lock锁的基本使用

在jdk1.5后新增的ReentrantLock类同样可达到此效果,且在使用上比synchronized更加灵活
相关API:
使用ReentrantLock实现同步
lock()方法:上锁
unlock()方法:释放锁
使用Condition实现等待/通知 类似于 wait()和notify()及notifyAll()
Lock锁底层基于AQS实现,需要自己封装实现自旋锁。

Synchronized —属于JDK 关键字 底层属于 C++虚拟机底层实现
Lock锁底层基于AQS实现-- 变为重量级
Synchronized 底层原理—锁的升级过程
Lock 过程中 注意 获取锁 释放锁

ReentrantLock用法
public class Thread09 implements Runnable {
    private int count = 100;
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(30);
            } catch (Exception e) {

            }
            try {
                // 获取锁
                lock.lock();
                if (count > 1) {
                    count--;
                    System.out.println(Thread.currentThread().getName() + "," + count);

                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Thread09 thread09 = new Thread09();
        Thread t1 = new Thread(thread09);
        Thread t2 = new Thread(thread09);
        t1.start();
        t2.start();
    }
}
Condition用法
public class Thread01 {
    private    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    public static void main(String[] args) throws InterruptedException {
        Thread01 thread01 = new Thread01();
        thread01.cal();
        Thread.sleep(3000);

        thread01.signal();
    }
    public void signal() {
        lock.lock();
        condition.signal();
        lock.unlock();
    }
    public void cal(){

        new Thread(new Runnable() {

            @Override
            public void run() {
                //子线程 需要主动释放锁,同时当前线程变为阻塞状态
                try {
                    lock.lock();
                    System.out.println(1);
                    //a开头 lock中的wait
                    condition.await();
                    System.out.println(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        }).start();
    }
}

多线程yield

主动释放cpu执行权
1.多线程yield 会让线程从运行状态进入到就绪状态,让后调度执行其他线程。
2.具体的实现依赖于底层操作系统的任务调度器


public class Thread02 extends Thread {
    public Thread02(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if (i == 30) {
                System.out.println(Thread.currentThread().getName() + ",释放cpu执行权");
                yield();
            }
            System.out.println(Thread.currentThread().getName() + "," + i);
        }


    }

    public static void main(String[] args) {
        new Thread02("1").start();
        new Thread02("2").start();
    }
}

多线程优先级

1.在java语言中,每个线程都有一个优先级,当线程调控器有机会选择新的线程时,线程的优先级越高越有可能先被选择执行,线程的优先级可以设置1-10,数字越大代表优先级越高
注意:Oracle为Linux提供的java虚拟机中,线程的优先级将被忽略,即所有线程具有相同的优先级。
所以,不要过度依赖优先级。
2.线程的优先级用数字来表示,默认范围是1到10,即Thread.MIN_PRIORITY到Thread.MAX_PRIORTY.一个线程的默认优先级是5,即Thread.NORM_PRIORTY
3.如果cpu非常繁忙时,优先级越高的线程获得更多的时间片,但是cpu空闲时,设置优先级几乎没有任何作用。

public class Thread03 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            int count = 0;
            for (; ; ) {
                System.out.println(Thread.currentThread().getName() + "," + count++);
            }
        }, "t1线程:");
        Thread t2 = new Thread(() -> {
            int count = 0;
            for (; ; ) {
                System.out.println(Thread.currentThread().getName() + "," + count++);
            }
        }, "t2线程:");
        t1.setPriority(Thread.MIN_PRIORITY);
        t1.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        t2.start();
    }
}

Join/Wait与sleep之间的区别

sleep(long)方法在睡眠时不释放对象锁
join(long)方法先执行另外的一个线程,在等待的过程中释放对象锁 底层是基于wait封装的,
Wait(long)方法在等待的过程中释放对象锁

1

评论区