zoukankan      html  css  js  c++  java
  • 多线程(下篇)

    多线程

    线程状态

    状态介绍

    1. new

      ​ 创建进入新生状态

    2. 就绪状态

      使用start方法立刻进入就绪状态,但是不一定会立刻执行

    3. 运行状态

      CPU调度运行时进入此状态

    4. 阻塞状态

      当调用sleep,wait或者同步锁订时。线程进入阻塞状态

    5. dead

      运行结束

    状态图

    线程停止

    1、线程自动停止

    2、利用标识符停止

    实例

    package com.py.demo01;
    
    public class TestStop implements Runnable {
    
        private boolean flag = true;
        int i = 0;
        @Override
        public void run() {
           //标志位
            while (flag){
                System.out.println("线程"+(i++));
            }
        }
    
        public void stop(){
            this.flag= false;
        }
    
    }
    class Test{
    
        public static void main(String[] args) {
            TestStop testStop = new TestStop();
            new Thread(testStop).start();
    
            for (int i = 0; i < 800; i++) {
                if (i==200){
                    testStop.stop();
                    System.out.println("=======线程结束======");
                }
                System.out.println("主线程"+i);
            }
        }
    }
    
    
    
    

    线程休眠

    特点

    sleep(t)t为休眠时间

    线程休眠结束后,进入就绪状态

    sleep会抛出InterruptedException异常

    sleep可以模拟网络延时、倒计时等

    每个对象又会有一个锁,sleep不会释放锁

    源码

    package com.py.demo01;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class TestSleep {
    
        public static void main(String[] args) {
    
            //倒计时执行
            try {
                countdown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            //获取系统当前时间
            Date time = new Date(System.currentTimeMillis());
            while (true){
    
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(time));
                try {
                    Thread.sleep(1000);
                    //刷新系统时间
                    time = new Date(System.currentTimeMillis());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
    
    
    
    //
        }
    
        //倒计时
        public static void countdown() throws InterruptedException {
            int time = 10;
            while (time!=0){
                System.out.println("倒计时"+ time);
                time--;
          Thread.sleep(1000);
            }
    
        }
    }
    
    

    线程礼让(yield)

    礼让不一定成功,具体情况看CPU调度

    demo

    package com.py.demo01;
    
    public class TestYield {
        public static void main(String[] args) {
            
            YeildDemo yeildDemo = new YeildDemo();
            
            new Thread(yeildDemo,"a").start();
            new Thread(yeildDemo,"b").start();
        }
    }
    //线程
    class YeildDemo implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"线程开始====>");
            //如果线程是a,此时将线程礼让出来
            if (Thread.currentThread().getName()=="a") {
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName()+"线程停止====>");
        }
    }
    
    

    线程加入(Join)

    当此线程结束后才可以执行其他线程,此时其他线程阻塞(可以理解为插队)

    demo:让大佬插主线程的队

    package com.py.demo01;
    
    public class TestJoin {
    
        public static void main(String[] args) {
    
            JoinTread thread = new JoinTread();
            //线程进入就绪态
            Thread join = new Thread(thread);
            join.start();
    
    
            for (int i = 0; i < 300; i++) {
                if (i==100){
                    try {
                        //线程开始插队
                        join.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("我是主线程"+ "	"+ i);
            }
    
        }
    
    
    
    }
    class JoinTread implements Runnable{
    
        @Override
        public void run() {
            //休眠的目的是让主线程可以跑到此线程的前面去
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (int i = 0; i < 200; i++) {
                System.out.println("大佬来了"+"	"+i);
            }
        }
    }
    
    
    
    

    线程的状态(State)

    常量

    • NEW
      尚未启动的线程处于此状态。
    • RUNNABLE
      在Java虚拟机中执行的线程处于此状态。
    • BLOCKED
      被阻塞等待监视器锁定的线程处于此状态。
    • WAITING
      正在等待另一个线程执行特定动作的线程处于此状态。
    • TIMED_WAITING
      正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    • TERMINATED
      已退出的线程处于此状态。

    Demo:使用主线程查看a线程状态

    package com.py.demo01;
    
    public class TestState implements Runnable {
    
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            TestState people = new TestState();
    
            //new状态
            Thread thread = new Thread(people,"a");
            Thread.State state = thread.getState();
            System.out.println(state);
    
            //就绪状态
            thread.start();
            state = thread.getState();
            System.out.println(state);
    
            while (state != Thread.State.TERMINATED){
                //打印当前状态
                try {
                    //0.1秒查看状态一次
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                state = thread.getState();
                System.out.println(state);
    
            }
            System.out.println("/////////////////////////");
    
        }
    }
    
    

    线程优先级(Priority)

    java提供线程调度器,当前所有准备状态的线程。线程调度器根据线程的优先级来决定线程的执行顺序。

    线程的优先度作为参考,但是实际情况要依据CPU调度进行处理

    Demo:优先级程度高的先执行

    package com.py.demo2;
    
    public class TestPriority implements Runnable {
    
        @Override
        public void run() { 
            System.out.println(Thread.currentThread().getName()+"	"+Thread.currentThread().getPriority());
        }
    
        public static void main(String[] args) {
            TestPriority testPriority = new TestPriority();
    
            Thread td01 = new Thread(testPriority);
            Thread td02 = new Thread(testPriority);
            Thread td03 = new Thread(testPriority);
            Thread td04 = new Thread(testPriority);
            Thread td05 = new Thread(testPriority);
    
    
            td01.setPriority(9);
            td01.start();
    
    
            td02.setPriority(4);
            td02.start();
    
    
            td03.setPriority(5);
            td03.start();
    
    
            td04.setPriority(7);
            td04.start();
    
    
            td05.setPriority(2);
            td05.start();
        }
    
    }
    
    

    守护线程(daemon)

    虚拟机会守护用户线程但是不会保证守护者线程完整执行

    当用户线程执行结束后,守护线程会被虚拟机停止

    Demo:自动结束的守护者线程

    package com.py.demo2;
    
    public class TestDaemon {
        public static void main(String[] args) {
            God god = new God();
            People people = new People();
    
            //设置God线程为守护者线程
            Thread thread = new Thread(god);
            thread.setDaemon(true);
            thread.start();
    
            //启动用户线程
            new Thread(people).start();
    
    
        }
    }
    //守护者线程
    class God implements Runnable{
    
        @Override
        public void run() {
            while (true){
                System.out.println("God will protecting you");
            }
        }
    }
    //用户线程
    class People implements Runnable{
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(" a wandfull year!!!!");
            }
    
            System.out.println("======BYE WORLD======");
        }
    }
    
    

    线程池

    类似于连接池,在线程池中创建线程,在有线程任务需要执行时,由线程池出线程,在线程任务结束之后将线程归还给线程池。

    线程池使用步骤:

    1、执行人 Executor类中提供的静态方法newFixedThreadPool(int nThreads),创建一个拥有几个线程的线程池。

    2、创建一个类,重写run() 方法,创建线程任务

    3、调用ExecutorService中的submit()方法,提交任务线程

    4、结束线程池使用ExecutorService 的shutdown()方法【不建议使用】

    package com.py.demo04;
    
    import java.util.concurrent.Executor;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 1、执行人 Executor类中提供的静态方法newFixedThreadPool(int nThreads),创建一个拥有几个线程的线程池。
     * 2、创建一个类,重写run() 方法,创建线程任务
     * 3、调用ExecutorService中的submit()方法,提交任务线程
     */
    
    public class DemoThreadpool {
        public static void main(String[] args) {
    
    //1、执行人 Executor类中提供的静态方法newFixedThreadPool(int nThreads),创建一个拥有几个线程的线程池。
            ExecutorService executorService = Executors.newFixedThreadPool(2);
    //     * 2、创建一个类,重写run() 方法,创建线程任务
            RunTasker tasker = new RunTasker();
    //     3、调用ExecutorService中的submit()方法,提交任务线程
            executorService.submit(tasker);
            executorService.submit(tasker);
            executorService.submit(tasker);
        }
    
    }
    
    

    线程锁

    线程同步机制

    并发

    多个线程执行同一个资源,并发指的是多个任务交替进行,

    同步

    线程同步实际上就是一种等待机制,多个同时需要访问此对象的线程进入对象的等待池形成队列

    知识延展

    同步VS异步

    同步和异步通常用来形容一次方法调用。同步方法调用开始后,调用者必须等待被调用的方法结束后,调用者后面的代码才能执行。而异步调用,指的是,调用者不用管被调用方法是否完成,都会继续执行后面的代码,当被调用的方法完成后会通知调用者。

    并发与并行

    并发和并行是十分容易混淆的概念。并发指的是多个任务交替进行,而并行则是指真正意义上的“同时进行”。实际上,如果系统内只有一个CPU,使用多线程时,在真实系统环境下不能并行,只能通过切换时间片的方式交替进行,从而并发执行任务。真正的并行只能出现在拥有多个CPU的系统中。

    阻塞和非阻塞

    阻塞和非阻塞通常用来形容多线程间的相互影响,比如一个线程占有了临界区资源,那么其他线程需要这个资源就必须进行等待该资源的释放,会导致等待的线程挂起,这种情况就是阻塞,而非阻塞就恰好相反,它强调没有一个线程可以阻塞其他线程,所有的线程都会尝试地往前运行。

    临界区

    临界区用来表示公共资源或者说是共享数据,可以被多个线程使用。但是每个线程使用时,一旦临界区资源被一个线程占有,那么其他线程必须等待。

    并发问题出现

    Demo01:经典买票问题

    package com.py.demo2;
    
    public class BuyTicket {
        public static void main(String[] args) {
            Buy station = new Buy();
            //三人分别买票
            new Thread(station,"张三").start();
            new Thread(station,"李四").start();
            new Thread(station,"王五").start();
        }
    
    }
    
    class Buy implements Runnable{
        //票数
        private int sum = 10;
        boolean flag = true;
        @Override
    
        public void run() {
    //        停止标志位
            while (flag){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //获得票的人
                System.out.println(Thread.currentThread().getName()+ "得到了第"+ sum--+"张票");
                //如果票没了就停止循环
                if (sum<=0){
                    flag = false;
                }
            }
        }
    }
    
    

    输出截图

    image-20200921104500331

    Demo02银行取钱问题

    package com.py.demo03;
    
    public class DrawingMoney {
        public static void main(String[] args) {
            //新建银行
            Bank bank = new Bank(10000, "账户");
            //取款操作01
            Drawing lisi = new Drawing(bank,40,"李四");
            lisi.start();
    
            //取款操作02
            Drawing wangwu = new Drawing(bank, 4000, "王五");
            wangwu.start();
    
        }
    }
    class Bank{
        //银行账户
          int account ;
          //操作人姓名
          String name;
    
        public Bank(int account, String name) {
            this.account = account;
            this.name = name;
        }
    
    }
    
    //取钱线程
    class Drawing extends Thread {
        //银行
        private Bank bank;
        //要取得的钱数
        private int draw;
        //取钱的人
        private String name;
    
        public Drawing(Bank bank, int draw, String name) {
            super(name);
            this.bank = bank;
            this.draw = draw;
        }
    
        @Override
        public void run() {
    
    
                if (bank.account - draw < 0){
                    System.out.println("账户余额不足,请重新设置取款金额");
                    return;
                }
                bank.account = bank.account - draw;
                System.out.println("取款人"+Thread.currentThread().getName()+"	余额"+bank.account);
    
        }
    }
    

    输出截图

    image-20200921155038664

    造成了李四读到了王五提交后的数据

    Synchronize

    理论点

    synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

    • 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
    • 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
    • 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
    • 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

    修饰一个代码块

    用static可以保证所需要的资源只有一份

    package com.py.demo03;
    
    /**
     * 同步线程
     */
    class SyncThread implements Runnable {
        private static int count;
    
        public SyncThread() {
            count = 0;
        }
    
        public void run() {
            synchronized(this) {
                for (int i = 0; i < 5; i++) {
                    try {
                        System.out.println(Thread.currentThread().getName() + ":" + (count++));
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public int getCount() {
            return count;
        }
    }
    
    class Man{
        public static void main(String[] args) {
            
    		/*       
    		//案例1、锁定对象SyncThread后,两个线程开始排队,形成互斥
    		 SyncThread syncThread = new SyncThread();
             Thread thread1 = new Thread(syncThread, "SyncThread1");
             Thread thread2 = new Thread(syncThread, "SyncThread2");
             thread1.start();
             thread2.start();*/
            
    		//案例2、锁定对象SyncThread后,两个线程互不干扰,但是因为static存在,所以还是使用的一份count
            Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
             Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
             thread1.start();
             thread2.start();
        }
    }
    

    案例一

    输出:

    SyncThread1:0
    SyncThread1:1
    SyncThread1:2
    SyncThread1:3
    SyncThread1:4
    SyncThread2:5
    SyncThread2:6
    SyncThread2:7
    SyncThread2:8
    SyncThread2:9

    总结:

    两个线程开始相互排队去执行run();一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞。

    案例二

    输出:

    SyncThread1:0
    SyncThread2:1
    SyncThread2:2
    SyncThread1:2
    SyncThread1:4
    SyncThread2:3
    SyncThread1:5
    SyncThread2:6
    SyncThread2:8
    SyncThread1:7

    总结

    这时创建了两个SyncThread的对象syncThread1和syncThread2,线程thread1执行的是syncThread1对象中的synchronized代码(run),而线程thread2执行的是syncThread2对象中的synchronized代码(run);我们知道synchronized锁定的是对象,这时会有两把锁分别锁定syncThread1对象和syncThread2对象,而这两把锁是互不干扰的,不形成互斥,所以两个线程可以同时执行。

    修饰一个方法

    同步方法也会把同步代码锁住,只让一个程序执行。锁的对象是类对象,也就是this。

    package com.py.demo03;
    
    /**
     * 同步线程
     */
    class SyncThread implements Runnable {
        private static int count;
    
        public SyncThread() {
            count = 0;
        }
    
        public synchronized void run() {
            for (int i = 0; i < 5; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ":" + (count++));
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public int getCount() {
            return count;
        }
    }
    
    class Man{
        public static void main(String[] args) {
            Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
             Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
             thread1.start();
             thread2.start();
        }
    }
    

    死锁

    多个线程同时抱有对方的需要的资源,导致程序阻塞。

    package com.py.demo03;
    
    public class TestLock {
        public static void main(String[] args) {
            Makeup thread01 = new Makeup(1,"李四");
            Makeup thread02 = new Makeup(0,"张三");
    
            thread01.start();
            thread02.start();
        }
    
    }
    class Pen{
    
    
    }
    
    class Peper{
    
    }
    class  Makeup extends Thread{
        //只有一份的笔 和  纸
        static Pen pen = new Pen();
        static Peper peper = new Peper();
    
        int choise;
        String user;
    
        public  Makeup(int choise,String user){
            this.user = user;
            this.choise = choise;
        }
    
        @Override
        public void run() {
            super.run();
            try {
                use();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public void use() throws InterruptedException {
            if (choise == 0 ){
                //第一个人先进来获得到笔的使用权
                synchronized (pen){
                    System.out.println(this.user + "获得到笔的使用权");
                    Thread.sleep(1000);
    
                    synchronized (peper){
                        System.out.println(this.user + "获得到纸的使用权");
                    }
                }
    
            }else{
                synchronized (peper){
                    System.out.println(this.user + "获得到纸的使用权");
    
                    synchronized (pen){
                        System.out.println(this.user + "获得到笔的使用权");
                    }
                }
            }
        }
    
    }
    
    package com.py.demo03;
    
    public class TestLock {
        public static void main(String[] args) {
            Makeup thread01 = new Makeup(1,"李四");
            Makeup thread02 = new Makeup(0,"张三");
    
            thread01.start();
            thread02.start();
        }
    
    }
    class Pen{
    
    
    }
    
    class Peper{
    
    }
    class  Makeup extends Thread{
        //只有一份的笔 和  纸
        static Pen pen = new Pen();
        static Peper peper = new Peper();
    
        int choise;
        String user;
    
        public  Makeup(int choise,String user){
            this.user = user;
            this.choise = choise;
        }
    
        @Override
        public void run() {
            super.run();
            try {
                use();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public void use() throws InterruptedException {
            if (choise == 0 ){
                //第一个人先进来获得到笔的使用权
                synchronized (pen){
                    System.out.println(this.user + "获得到笔的使用权");
                    Thread.sleep(1000);
    
                    synchronized (peper){
                        System.out.println(this.user + "获得到纸的使用权");
                    }
                }
    
            }else{
                synchronized (peper){
                    System.out.println(this.user + "获得到纸的使用权");
    
                    synchronized (pen){
                        System.out.println(this.user + "获得到笔的使用权");
                    }
                }
            }
        }
    
    }
    

    程序卡死

    image-20200923095846688

    lock锁

    与Synchronize相同,

    不同之处,Lock是显锁(手动开启和关闭锁)synchronize是隐式锁,出了作用域自动释放

    lock只有代码块锁,synchronized有代码块和方法锁。

    lock锁性能更好,并且具有更好的扩展性

    上锁与解锁

    void lock(); 上锁

    void unlock; 解锁

    package com.py.demo03;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 同步线程
     */
    class SyncThread implements Runnable {
        private static int count;
    
        public SyncThread() {
            count = 0;
        }
        //线程锁对象
         Lock lock = new ReentrantLock();
    
        public  void run() {
    
            for (int i = 0; i < 5; i++) {
                lock.lock();
                try {
                    Thread.sleep(500);
                    System.out.println(Thread.currentThread().getName() + ":" + (count++));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //解锁
                    lock.unlock();
                }
            }
        }
    
        public int getCount() {
            return count;
        }
    }
    
    class Man{
        public static void main(String[] args) {
             SyncThread syncThread = new SyncThread();
             Thread thread1 = new Thread(syncThread, "SyncThread1");
             Thread thread2 = new Thread(syncThread, "SyncThread2");
             thread1.start();
             thread2.start();
    
        }
    }
    

    唤醒线程

    线程休眠之后,由其他线程唤醒。

    带参数的休眠方法:wait(time);时间达到之后自动唤醒

    全部唤醒:notifyAll();

    唤醒的是第一个进入锁对象 的线程,

    休眠的是第一个进入锁对象 的线程,

    package com.py.demo03;
    
    /**
     * 等待唤醒案例
     * 顾客告知老板需要的食品的数量和种类,唤醒老板线程然后自己休息
     * 老板开始生产,生产完成后唤醒顾客线程
     *  老板和顾客只能一个在执行
     *  只有锁对象才能waiter notify
     */
    public class DemoWait extends Thread{
    
    
    
        public static void main(String[] args) {
            //创建唯一锁
            Object obj = new Object();
            //顾客线程
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    synchronized (obj){
                        //顾客告知老板需要的食品的数量和种类
                        System.out.println("要吃什么样的,要多少");
                        try {
                            //然后自己休息
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("吃完了走人");
                    }
                }
            }.start();
    
            //老板线程
            new Thread(){
                @Override
                public void run() {
                    //老板等待顾客叫完东西
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    super.run();
                    synchronized (obj){
                        //老板开始生产,
                        System.out.println("老板开始制作");
                        //生产完成后唤醒顾客线程
                        obj.notify();
                    }
                }
            }.start();
        }
    
    
    }
    
    

    线程通信

    理论:

    多线程并发执行时,在默认情况下cpu随机切换线程,当我们需要一个的多线程共同完成一件任务时,希望他们可以有顺序的执行,于是需要他们线程之间进行通信。

  • 相关阅读:
    Shiro
    Python活力练习Day11
    Python活力练习Day10
    Python活力练习Day9
    数据框DataFrame和列表List相互转换
    Python活力练习Day8
    Python中绘制箭头
    Python活力练习Day7
    Python活力练习Day6
    Python活力练习Day5
  • 原文地址:https://www.cnblogs.com/yuknight/p/13740646.html
Copyright © 2011-2022 走看看