A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 逆风TO 于 2020-3-10 11:22 编辑

解决多线程当中共享资源冲突的问题1. 冲突问题展示:
[Java] 纯文本查看 复制代码
/*
 * 共享资源冲突的问题
 */
class SingleThread implements Runnable {

        // 共享资源,100张票
        private static int ticket = 100;

        @Override
        public void run() {
                while (true) {
                        if (ticket > 0) {
                                System.out.println(Thread.currentThread().getName() +
                                 "售出了第" + ticket + "张票");
                                ticket -= 1;
                                
                                try {
                                        Thread.sleep(100);
                                } catch (InterruptedException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                }
                        } else {
                                System.out.println(Thread.currentThread().getName() +
                                 "售罄!!!");
                                break;
                        }
                }
        }
}

public class Demo1 {
        public static void main(String[] args) {
                Thread thread = new Thread(new SingleThread(),"淘票票");
                Thread thread2 = new Thread(new SingleThread(),"猫眼");
                Thread thread3 = new Thread(new SingleThread(),"美团");
                
                thread.start();
                thread2.start();
                thread3.start();
        }
}



从上面的例子上可以看到,最后一张票被每一个平台都卖了一次,这样子肯定是不符合实际情况的,这就是本次我们需要解决的问题。

2. 解决方法:2.1 同步代码块  1.格式:
[Java] 纯文本查看 复制代码
synchronized ("锁") {[/b][b]//需要同步的代码[/b][/size][list=1]
[*][size=2]}


2.特征:
a: synchronized关键字后面的小括号里面的对象是锁对象,并且要求如果是多线程的情况下,锁对象必须是唯一的。
b: synchronized后大括号中的代码就是需要同步的代码,或者说加锁的代码,大括号里面的内容一次有且只允许一个线程类对象进入执行的操作,其余的线程类对象需要等待该线程类对象开锁才能进入。
c: 同步代码块中的代码越短越好,在保证足够安全的情况下,提高性能。

[Java] 纯文本查看 复制代码
// 1. 使用同步代码块解决多线程中共享资源冲突的问题
 
/**
 * 自定义售票线程类
 * 
 * @author 
 *
 */
//同步代码块
class SingleThread1 implements Runnable {

        // 共享资源,100张票
        private static int ticket = 100;

        @Override
        public void run() {
                while (true) {
                        synchronized ("锁") {

                                if (ticket > 0) {
                                        System.out.println(Thread.currentThread().getName() +
                                         "售出了第" + ticket + "张票");
                                        ticket -= 1;

                                        try {
                                                Thread.sleep(100);
                                        } catch (InterruptedException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }
                                } else {
                                        System.out.println(Thread.currentThread().getName() +
                                         "售罄!!!");
                                        break;
                                }
                        }
                }
        }
}

public class Demo2 {
        public static void main(String[] args) {
                Thread thread = new Thread(new SingleThread1(), "淘票票");
                Thread thread2 = new Thread(new SingleThread1(), "猫眼");
                Thread thread3 = new Thread(new SingleThread1(), "美团");

                thread.start();
                thread2.start();
                thread3.start();
        }
}

2.2 同步方法
什么是同步方法:使用synchronized关键字修饰的方法就是同步方法,同步方法一次有且只允许一个线程类对象进入执行操作。
2.2.1 静态同步方法
静态方法使用synchronized关键字修饰就是静态同步方法,静态同步方法的锁对象是当前类对应的字节码文件,是唯一的。
如果是选择静态同步方法的话,因为锁对象是.class字节码文件,具有唯一性,多个线程使用的锁是同一个。

[Java] 纯文本查看 复制代码
// 2.1 使用静态成员方法解决多线程中共享资源冲突的问题
/**
 * 自定义售票线程类
 * 
 * @author 
 *
 */
//同步方法
class SingleThread3 implements Runnable {

        // 共享资源,100张票
        private static int ticket = 100;

        @Override
        public void run() {
                while (true) {
                        sellTicket();
                        if(ticket <= 0) {
                                break;
                        }
                }
        }

        // 静态同步方法
        public static synchronized void sellTicket() {
                if (ticket > 0) {
                        System.out.println(Thread.currentThread().getName() +
                         "售出了第" + ticket + "张票");
                        ticket -= 1;

                        try {
                                Thread.sleep(100);
                        } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                } else {
                        System.out.println(Thread.currentThread().getName() + "售罄!!!");
                }
        }
}

public class Demo3 {
        public static void main(String[] args) {
        //使用静态同步方法
                Thread thread1 = new Thread(new SingleThread3(), "淘票票");
                Thread thread2 = new Thread(new SingleThread3(), "猫眼");
                Thread thread3 = new Thread(new SingleThread3(), "美团");

                thread1.start();
                thread2.start();
                thread3.start();
        }
}

2.2.2 非静态同步方法
  • 非静态方法使用synchronized关键字修饰的就是非静态同步方法,非静态同步方法的锁对象是当前类对象 - this。
  • 如果是非静态同步方法的话,需要保证执行的线程类对象目标代码只有一个,因为锁对象为当前类对象。
[Java] 纯文本查看 复制代码
// 2.2 使用静态成员方法解决多线程中共享资源冲突的问题[/size]
[size=16px]/**[/size]
[size=16px] * 自定义售票线程类[/size]
[size=16px] * [/size]
[size=16px] * @author [/size]
[size=16px] *[/size]
[size=16px] */[/size]
[size=16px]//同步方法[/size]
[size=16px]class SingleThread3 implements Runnable {[/size]

[size=16px]        // 共享资源,100张票[/size]
[size=16px]        private static int ticket = 100;[/size]

[size=16px]        @Override[/size]
[size=16px]        public void run() {[/size]
[size=16px]                while (true) {[/size]
[size=16px]                        sellTicket();[/size]
[size=16px]                        if(ticket <= 0) {[/size]
[size=16px]                                break;[/size]
[size=16px]                        }[/size]
[size=16px]                }[/size]
[size=16px]        }[/size]
[size=16px]        [/size]
[size=16px]        //非静态同步方法[/size]
[size=16px]        public synchronized void sellTicket() {[/size]
[size=16px]                if (ticket > 0) {[/size]
[size=16px]                        System.out.println(Thread.currentThread().getName() +[/size]
[size=16px]                         "售出了第" + ticket + "张票");[/size]
[size=16px]                        ticket -= 1;[/size]

[size=16px]                        try {[/size]
[size=16px]                                Thread.sleep(100);[/size]
[size=16px]                        } catch (InterruptedException e) {[/size]
[size=16px]                                // TODO Auto-generated catch block[/size]
[size=16px]                                e.printStackTrace();[/size]
[size=16px]                        }[/size]
[size=16px]                } else {[/size]
[size=16px]                        System.out.println(Thread.currentThread().getName() +[/size]
[size=16px]                         "售罄!!!");[/size]
[size=16px]                }[/size]
[size=16px]        }[/size]

[size=16px]}[/size]

[size=16px]public class Demo3 {[/size]
[size=16px]        public static void main(String[] args) {[/size]
[size=16px]                //使用非静态同步方法[/size]
[size=16px]                //使用同一个目标代码对象[/size]
[size=16px]                SingleThread3 singleThread3 = new SingleThread3();[/size]
[size=16px]                Thread thread1 = new Thread(singleThread3,"淘票票");[/size]
[size=16px]                Thread thread2 = new Thread(singleThread3,"猫眼");[/size]
[size=16px]                Thread thread3 = new Thread(singleThread3,"美团");[/size]
[size=16px]        }[/size]
[size=16px]}[/size]
[size=16px]

2.3 Lock锁
  • 对象化操作:Lock lock = new ReentramtLock( );
  • 加锁:lock.lock( );
  • 开锁:lock.unlock( );
    [Java] 纯文本查看 复制代码
    // 使用静态Lock锁解决共享资源冲突的问题[/size]
    /**
     * 自定义售票线程类
     * 
     * @author 
     *
     */
    //lock加锁操作
    class SingleThread4 implements Runnable {
    
            // 共享资源,100张票
            private static int ticket = 100;
            
            //创建锁对象,这里使用的是静态的方式,锁对象是唯一的
            static Lock lock = new ReentrantLock();
    
            @Override
            public void run() {
                    while (true) {
                                    
                            //加锁
                            lock.lock();
                                    if (ticket > 0) {
                                            System.out.println(Thread.currentThread().getName() +
                                             "售出了第" + ticket + "张票");
                                            ticket -= 1;
    
                                            try {
                                                    Thread.sleep(100);
                                            } catch (InterruptedException e) {
                                                    // TODO Auto-generated catch block
                                                    e.printStackTrace();
                                            }
                                    } else {
                                            System.out.println(Thread.currentThread().getName() +
                                             "售罄!!!");
                                            break;
                                    }
                            lock.unlock();
                    }
            }
    }
    
    public class Demo4 {
            public static void main(String[] args) {
                    Thread thread = new Thread(new SingleThread4(), "淘票票");
                    Thread thread2 = new Thread(new SingleThread4(), "猫眼");
                    Thread thread3 = new Thread(new SingleThread4(), "美团");
    
                    thread.start();
                    thread2.start();
                    thread3.start();
            }
    }
    







166 个回复

倒序浏览
回复 使用道具 举报
学习到很多
回复 使用道具 举报
加油                     
回复 使用道具 举报
学习到很多
回复 使用道具 举报
回复 使用道具 举报
学习到很多
回复 使用道具 举报
多线程是不是很难呀    好难呀  哈哈哈  谢谢楼主的分享
回复 使用道具 举报
6666666666666666666666666666666666666
回复 使用道具 举报
6666666666666666
回复 使用道具 举报
666666666666666666666666666666666666
回复 使用道具 举报
面试重点呀  感谢楼主的分享   优秀   棒棒棒
回复 使用道具 举报
duanshaobo 来自手机 中级黑马 2020-3-24 16:34:45
13#
六六六六六六六六六
回复 使用道具 举报

学习到很多
回复 使用道具 举报

学习到很多
回复 使用道具 举报
咨询部王丹 来自手机 中级黑马 2020-3-25 09:48:35
16#
努力加油了!!!
回复 使用道具 举报
棒棒的
回复 使用道具 举报
回复 使用道具 举报

棒棒的
棒棒的
棒棒的
棒棒的
回复 使用道具 举报

感谢分享  加油哦~
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马