zoukankan      html  css  js  c++  java
  • java的多线程学习,第二记

    多线程带来便利的同时,也会带来麻烦

    1,操作同一个共享资源的时候,会带来很多意想不到的麻烦。

    就像卖票一样,如果不考虑多线程的环境,那肯定是没有问题的。

    package secondSteps;
    
    /**
     * 卖票
     * @author liugang
     * @create 2018/12/6 22:43
     **/
    public class SellTicket implements Runnable {
    
        private Integer ticketCount = 100;
    
        @Override
        public void run() {
            try {
                while (ticketCount>0){
                    sellTicket();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        private void sellTicket() {
            if (ticketCount>0){
                ticketCount--;
                System.out.println("线程的名称:"+Thread.currentThread().getName()+"卖票 还剩"+ticketCount+"张");
            }else{
                System.out.println("票卖完了");
            }
        }
        //如果不考虑多线程的环境,肯定不会出问题
    }
    public static void main(String[] args) {
            SellTicket ticket = new SellTicket();
            Thread t1 = new Thread(ticket,"窗口1");
            t1.start();
        }

    运行的状况:票是一张一张的少的。

    现在开四个线程卖票

    public static void main(String[] args) {
            SellTicket ticket = new SellTicket();
            Thread t1 = new Thread(ticket,"窗口1");
            Thread t2 = new Thread(ticket,"窗口1");
            Thread t3 = new Thread(ticket,"窗口1");
            Thread t4 = new Thread(ticket,"窗口1");
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }

    出现这种情况,是cpu高速切换,线程1,还没有执行完,在条件判断的时候,就切换到其他的线程。

    多线程解决一个共享资源的占用问题是个头疼的问题

    java提供了一定的解决办法。

    操作共享资源的时候,不要竞争,一个一个来。比如,春节的时候在火车上厕所,一个人进去了把门锁了,方便之后开门,出来了。

    给代码加个锁,就可以搞定这个问题。java提供了关键字synchronized,这个关键字代码块是要上锁的。那上什么锁呢,万物皆可superme

    private Object obj = new Object();
    private void sellTicket() {
            synchronized (obj){
                if (ticketCount>0){
                    ticketCount--;
                    System.out.println("线程的名称:"+Thread.currentThread().getName()+"卖票 还剩"+ticketCount+"张");
                }else{
                    System.out.println("票卖完了");
                }
            }
        }

    对象是有一个标志位的,当前锁定这个标志位,另外一个线程进来了,发现标志位没改变,就动不了。

    synchronized (this)//同步代码块, 锁  任何一个对象

    锁自己,刚不刚,强不强,也一样的,万物皆可superme

    还有可以把方法同步一样,把方法加个synchronized也一样,用哪种方法,就看自己的需求了。

    代码块的好处:同步代码弄成最小的范围,提高效率。

    同步方法就是 this,就是把当前对象锁了

    静态方法锁,顾名思义,静态的方法锁,加个static

    package secondSteps;
    
    /**
     * 卖票
     * @author liugang
     * @create 2018/12/6 22:43
     **/
    public class SellTicket implements Runnable {
    
        private static Integer ticketCount = 100;
    
        private Object obj = new Object();
    
        @Override
        public void run() {
            try {
                while (ticketCount>0){
                    sellTicket();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        private synchronized static void sellTicket() {
            //同步代码块 锁 任何一个对象
            synchronized (SellTicket.class) {
                if (ticketCount > 0) {
                    ticketCount--;
                    System.out.println("线程的名称:" + Thread.currentThread().getName() + "卖票 还剩" + ticketCount + "张");
                } else {
                    System.out.println("票卖完了");
                }
            }
        }
        //如果不考虑多线程的环境,肯定不会出问题
    }

    用static锁的是整个类,这样你new 出来的对象是没关系的,火车上4个人排队上一个厕所。

    多个线程要同一个锁才可以。

    注意:

    1,同步代码块,他可以用任何一个对象作为锁

    2,静态方法锁,锁的是整个类,所有对象过来都会阻塞,static是类级别,并不是某个对象。

    3,synchronized方法,是锁的对象,这样是不行的。各所各的,是不一样的,是没有意思的。

    线程的等待,线程的唤醒:

    1,wait   ----->导致获得这个锁的线程,阻塞等待,知道他被唤醒为止

    2,notify ----->唤醒在等待这个锁的其他线程之一

    3,notifyall  ------->唤醒所有在等待的这个线程

    package threeSteps;
    
    /**
     * 以这个类作为锁,让其他的类去等待,去唤醒
     * @author liugang
     * @create 2018/12/6 23:30
     **/
    public class Message {
    
        private String msg;
    
        public Message(String msg) {
            this.msg = msg;
        }
    
        public Message() {
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    package threeSteps;
    
    /**
     * @author liugang
     * @create 2018/12/6 23:32
     **/
    public class Waiter implements Runnable{
    
        private Message msg;
    
        public Waiter(Message msg) {
            this.msg = msg;
        }
    
        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            //当前线程,执行到了msg.wait()就会导致,持有这个锁的线程进行等待,一直到他被唤醒为止
            synchronized (msg){
                try {
                    System.out.println(name+"等待");
                    msg.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
            Message msg = new Message("锁");
            //同一个对象,同一个锁才行
            Waiter waiter = new Waiter(msg);
            new Thread(waiter,"waiter").start();
    
            Waiter waiter1 = new Waiter(msg);
            new Thread(waiter1,"waiter1").start();
            
            Notifier notifier = new Notifier(msg);
            new Thread(notifier,"waiter").start();
        }

    运行结果如下:

    这是因为我把notify改成notifyAll,唤醒所有了

    package threeSteps;
    
    /**
     * 进行唤醒
     * @author liugang
     * @create 2018/12/6 23:38
     **/
    public class Notifier implements Runnable{
    
        private Message msg;
    
        public Notifier(Message msg) {
            this.msg = msg;
        }
    
        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            synchronized (msg){
                msg.setMsg("唤醒线程工作");
    //            msg.notify();
                msg.notifyAll();
            }
        }
    }

    wait运行到msg.wait()就卡死了,就一直等这了,就像我的联想笔记本动不动就卡死了,

    好在有notify唤醒他,而我的笔记本就只能重启由我自己来唤醒他啦。

    notify只能唤醒一个哟,另外一个只能一直卡死在那了。

    notifyAll就唤醒所有,就像毛主席,是的

  • 相关阅读:
    25-k个一组翻转链表 203-移除链表元素 206-反转一个链表
    24. 两两交换链表中的节点
    23-合并K个升序链表
    19-删除链表的倒数第N个节点
    18-四数之和
    21-合并两个有序链表
    双指针
    16-最接近的三数之和
    15-三数之和
    RobotFramework 断言关键字
  • 原文地址:https://www.cnblogs.com/fuckingPangzi/p/10080521.html
Copyright © 2011-2022 走看看