精华内容
下载资源
问答
  • 多线程高并发怎么解决方案
    2020-11-23 20:16:46

    多线程怎么解决高并发?
    synchronized关键字主要解决多线程共享数据同步问题。
    ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。
    ThreadLocal和Synchonized都用于解决多线程并发访问但是ThreadLocal与synchronized有本质的区别:
    synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal是为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

    更多相关内容
  • 在基础学习中,我们简单的从多线程的角度去了解最基础的并发解决方案。 还是以多窗口卖票为例 一个Thread的子类完成卖票方法。 这里在测试类中可以开启多个线程来访问同一个成员变量t,会导致卖票数量不精确种种情况...

    在学习多线程的时候,会知道在java的实际开发中经常出现高并发的问题,也就是同一资源或者说网站被多线程或者说多用户同时访问导致的线程不安全,易引起网站挂掉的情况称之为高并发。
    在基础学习中,我们简单的从多线程的角度去了解最基础的并发解决方案。

    还是以多窗口卖票为例
    一个Thread的子类完成卖票方法。
    这里在测试类中可以开启多个线程来访问同一个成员变量t,会导致卖票数量不精确种种情况。
    用第一个解决方案: 同步代码块synchronized(){}
    其中()内的参数必须是唯一性。字节码对象也可以,一个是字符串等等都可以;
    synchronzied也可以直接同步方法,直接写在修饰符之前,不过必须加上static修饰保证方法对所有对象共享。

    package cn.itsource.SaleTicket;
    
    public class SafeTicketDemo extends Thread {
    	static int t = 100;
    	static String str = "嘿嘿";
    	@Override
    	//复写Thread中的run方法
    	public void run() {
    		while(t>0){
    			synchronized (str) {
    				if(t>0){
    					System.out.println(this.getName()+"票号为:"+t);
    					t--;
    				}
    			}
    		}
    	}
    }
    

    也可以使用第二种方法:加锁Lock类方法
    需要注意的是lock加锁后必须用finally来保证锁的释放

    package cn.itsource.SaleTicket;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class SafeTicketDemo2 implements Runnable {
    	static int t = 100;
    	static Lock l = new ReentrantLock();
    	@Override
    	//复写run方法
    	public void run() {
    		while(t>0){
    			//上锁
    			l.lock();
    			try{
    				if(t>0){					
    				System.out.println(Thread.currentThread().getName()+"票号为:"+t);
    					t--;
    				}
    			}finally{
    				//释放锁
    				l.unlock();
    			}	
    		}
    	}
    }
    
    展开全文
  • 多线程&并发-实例与解决方案

    千次阅读 2020-06-23 11:27:24
    java中你知道哪些锁? 问题回答: 乐观锁/悲观锁 共享锁/独享锁 公平锁/非公平锁 互斥锁/读写锁 可重入锁 自旋锁 分段锁 偏向锁/轻量级锁/重量级锁...2.就绪/运行(RUNNABLE):该状态包含了经典线程模型的两种状态:就
    java中你知道哪些锁?

    问题回答
    乐观锁/悲观锁
    共享锁/独享锁
    公平锁/非公平锁
    互斥锁/读写锁
    可重入锁
    自旋锁
    分段锁
    偏向锁/轻量级锁/重量级锁

    辅助理解:
    在这里插入图片描述

    Java线程的状态或者生命周期?

    问题回答

    • Java的线程状态被定义在公共枚举类java.lang.Thread.state中。一种有六种状态
      1.新建(NEW):表示线程新建出来还没有被启动的状态,比如:Thread t = new MyThread();
      2.就绪/运行(RUNNABLE):该状态包含了经典线程模型的两种状态:就绪(Ready)、运行(Running):
      3.阻塞(BLOCKED):通常与锁有关系,表示线程正在获取有锁控制的资源,比如进入synchronized代码块,获取ReentryLock等;发起阻塞式IO也会阻塞,比如字符流字节流操作。
      4.等待(WAITING):线程在等待某种资源就绪。
      5.超时等待(TIMED_WAIT):线程进入条件和等待类似,但是它调用的是带有超时时间的方法。
      6.终止(TERMINATED):线程正常退出或异常退出后,就处于终结状态。也可以叫线程的死亡。

    • 经典线程模型包含5种状态,:新建、就绪、运行、等待、退出

    • 经典线程的就绪、运行,在java里面统一叫RUNNABLE

    • Java的BLOCKED、WAITING、TIMED_WAITING都属于传统模型的等待状态

    synchronized 与lock区别?

    问题回答
    1.lock是一个接口,而synchronized是java的一个关键字
    2.synchronized异常会释放锁,lock异常不会释放,所以一般try catch包起来,finally中写入unlock,避免死锁。
    3.Lock可以提高多个线程进行读操作的效率
    4.synchronized关键字,可以放代码块,实例方法,静态方法,类上
    5.lock一般使用ReentrantLock类做为锁,配合lock()和unlock()方法。在finally块中写unlock()以防死锁。
    6.jdk1.6之前synchronized低效。jdk1.6之后synchronized高效。

    synchronized 与ReentrantLock区别?

    问题回答
    1.synchronized依赖JVM实现,ReentrantLock是JDK实现的。synchronized是内置锁,只要在代码开始的地方加synchronized,代码结束会自动释放。Lock必须手动加锁,手动释放锁。
    2.ReenTrantLock比synchronized增加了一些高级功能。synchronized代码量少,自动化,但扩展性低,不够灵活;ReentrantLock扩展性好,灵活,但代码量相对多。
    3.两者都是可重入锁。都是互斥锁。
    4.synchronized是非公平锁,ReentrantLock可以指定是公平锁还是非公平锁。

    synchronized 与ThreadLocal区别?

    1.都是为了解决多线程中相同变量的访问冲突问题。
    2.Synchronized同步机制,提供一份变量,让不同的线程排队访问。
    3.ThreadLocal关键字,为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
    4.ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

    synchronized 与volatile区别?

    1.volatile是一个类型修饰符(type specifier)。
    2.volatile,它能够使变量在值发生改变时能尽快地让其他线程知道。
    3.关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且只能修改变量,而synchronized可以修饰方法,以及代码块。
    4.多线程访问volatile不会发生阻塞,而synchronized会出现阻塞
    volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做同步
    5.关键字volatile解决的下变量在多线程之间的可见性;而synchronized解决的是多线程之间资源同步问题

    Thread类中的start()和run()方法有什么区别?

    1.通过调用线程类的start()方法来启动一个线程,使线程处于就绪状态,即可以被JVM来调度执行,在调度过程中,JVM通过调用线程类的run()方法来完成实际的业务逻辑,当run()方法结束后,此线程就会终止。
    2.如果直接调用线程类的run()方法,会被当作一个普通的函数调用,程序中仍然只有主线程这一个线程。即start()方法能够异步的调用run()方法,但是直接调用run()方法却是同步的,无法达到多线程的目的。
    3.因此,只用通过调用线程类的start()方法才能达到多线程的目的。

    事务的隔离级别及引发的问题
    • 4个隔离级别
    • 读未提交、读已提交、可重复读、串行化
    • 分别怎么理解呢?
      读未提交(READ UNCOMMITTED),事务中的修改,即使没有提交,对其它事务也是可见的。
      读已提交(READ COMMITTED),一个事务能读取已经提交的事务所做的修改,不能读取未提交的事务所做的修改。也就是事务未提交之前,对其他事务不可见。
      可重复读(REPEATABLE READ),保证在同一个事务中多次读取同样数据的结果是一样的。
      串行化(SERIALIZABLE),强制事务串行执行。
    • 读已提交是sql server的默认隔离级别。
    • 可重复读是mysql的默认隔离级别。
    • 多个事务,各个隔离级别引起的问题
      读未提交:可能出现脏读、不可重复度、幻读;
      读已提交:可能出现不可重复度、幻读;
      可重复读:可能出现幻读;
      串行化:都没问题;
    什么是线程安全,java如何保证线程安全?
    • 在多线程环境中,能永远保证程序的正确性。执行结果不存在二义性。说白了,运行多少次结果都是一致的。
    • 换种说法,当多个线程访问某一个类(对象或方法)时,这个类始终都能表现心正确的行为,那么这个类(对象或方法)就是线程安全的。
    • 使用synchronized关键字和使用锁。
    介绍一下线程池?
    • 线程池就是预先创建一些线程,它们的集合称为线程池。
    • 线程池可以很好地提高性能,在系统启动时即创建大量空闲的线程,程序将一个task给到线程池,线程池就会启动一条线程来执行这个任务,执行结束后,该线程不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
    • 线程的创建和销毁比较消耗时间,线程池可以避免这个问题。
    • Executors是jdk1.5之后的一个新类,提供了一些静态方法,帮助我们方便的生成一些常见的线程池
      newSingleThreadExecutor:创建一个单线程化的Executor。
      newFixedThreadPool:创建一个固定大小的线程池。
      newCachedThreadPool:创建一个可缓存的线程池
      newScheduleThreadPool:创建一个定长的线程池,可以周期性执行任务。
    • 我们还可以使用ThreadPoolExecutor自己定义线程池,弄懂它的构造参数即可
      int corePoolSize,//核心池的大小
      int maximumPoolSize,//线程池最大线程数
      long keepAliveTime,//保持时间/额外线程的存活时间
      TimeUnit unit,//时间单位
      BlockingQueue workQueue,//任务队列
      ThreadFactory threadFactory,//线程工厂
      RejectedExecutionHandler handler //异常的捕捉器

    简要回答

    • 线程池就是预先创建一些线程
    • 线程池可以很好地提高性能
    • 线程池可以避免线程的频繁创建和销毁
    • Executors可以创建常见的4种线程(单线程池、固定大小的、可缓存的、可周期性执行任务的)。
      可以通过ThreadPoolExecutor自己定义线程池。
    同步和异步有何异同?
    • 同步发了指令,会等待返回,然后再发送下一个。
    • 异步发了指令,不会等待返回,随时可以再发送下一个请求
    • 同步可以避免出现死锁,读脏数据的发生
    • 异步则是可以提高效率
    • 实现同步的机制主要有临界区、互斥、信号量和事件
    如何异步获取多线程返回的数据?

    问题包含
    说一下Callable这个接口的理解?
    说一下Future接口的理解?
    说一下FutureTask类的理解?
    说一下CompletionService接口的理解?

    问题回答

    • 通过Callable+Future,Callable负责执行返回,Future负责接收。Callable接口对象可以交给ExecutorService的submit方法去执行。
    • 通过Callable+FutureTask,Callable负责执行返回,FutureTask负责接收。FutureTask同时实现了Runnable和Callable接口,可以给到ExecutorService的submit方法和Thread去执行。
    • 通过CompletionService,jdk1.8之后提供了完成服务CompletionService,可以实现这样的需求。
    • 注意,实现Runnable接口任务执行结束后无法获取执行结果。
    如何自定义线程池?

    问题回答

    • 通过ThreadPoolExecutor创建
    • 弄懂它的7个构造参数即可
      int corePoolSize,//核心池的大小
      int maximumPoolSize,//线程池最大线程数
      long keepAliveTime,//保持时间/额外线程的存活时间
      TimeUnit unit,//时间单位
      BlockingQueue workQueue,//任务队列
      ThreadFactory threadFactory,//线程工厂
      RejectedExecutionHandler handler //异常的捕捉器
    工作中哪些地方使用了多线程?
    • 一般业务,web层–> service层 -->dao --> sql基本用不到多线程
    • 数据量很大(1000w级别、TB级别)的I/O操作,可以考虑多线程
    • 举一些例子
      自己做并发测试的时候,假如想写想模拟3000个并发请求。
      多线程下单抢单,假如支持5000人的并发下单。
      多线程写入mysql,假如有1000w条数据要入库。
      多线程写入redis,假如有1000w的数据要存入redis。
      多线程导入ES索引,假如有1000w的数据要添加到ES索引。
      poi多线程导出,假如xls里面有10w的数据需要导出。
      poi多线程导入,假如有10w条数据需要导入到xls。
      多线程发送邮件,假如有10w用户需要发送邮件。
      多线程发送短信,假如有10w用户需要发送邮件。
      多线程备份日志,假如10tb日志文件要备份。
      多线程验证数据,比如验证url是否存在,假如有100w个url。
    展开全文
  • 多线程并发问题和解决方案

    千次阅读 2020-11-23 14:39:29
    问题原型:线程操作同一个对象 —> 买火车票 package com.baiyi.exercise; /** * @author 白衣 * @Description: 火车买票 * @Date 2020/11/22 */ public class Ticks implements Runnable{ private ...

    并发问题

    在这里插入图片描述

    1. 初识并发问题

    问题原型:多个线程操作同一个对象 —> 买火车票

    package com.baiyi.exercise;
    
    /**
     * @author 白衣
     * @Description: 火车买票
     * @Date 2020/11/22
     */
    public class Ticks implements Runnable{
        private int tickNum = 10;
        @Override
        public void run() {
            while (true){
                if (tickNum <= 0){
                    break;
                }
                try {
                    Thread.sleep(200);
                    System.out.println(Thread.currentThread().getName() + "-->拿到了第" + tickNum-- + "票");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            Ticks ticks = new Ticks();
            new Thread(ticks, "小明").start();
            new Thread(ticks, "老师").start();
            new Thread(ticks, "黄牛党").start();
        }
    }
    
    - 结果分析:
    小明-->拿到了第9票
    老师-->拿到了第8票
    黄牛党-->拿到了第10票
    小明-->拿到了第7票
    黄牛党-->拿到了第5票
    老师-->拿到了第6票
    小明-->拿到了第4票
    黄牛党-->拿到了第4票
    老师-->拿到了第3票
    小明-->拿到了第2票
    老师-->拿到了第1票
    黄牛党-->拿到了第2票
    
    - 出现了两次第 2 张票,说明多个线程操作同一个资源,出现了线程不安全,数据紊乱的问题。
    

    2. 线程同步

    • 现实生活中,我们会遇到“同一个资源,多个人都想使用”的问题,比如,食堂排队打饭,每个人都想吃饭,最天然的解决方法就是排队,一个个来。

    • 处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。这时我们就需要线程同步。

    • 什么是线程同步:线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个 对象的等待池 形成队列,等待前面线程使用完毕,下一个线程再使用。

    • 怎么实现线程同步: 队列 + 锁

    • 存在问题:
      由于同一个进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题。

    • 解决方案:
      为了保证数据在方法中被访问时的正确性,在访问时加入 锁机制 synchronized,当一个线程获得对象的排它锁、独占资源,其他线程必须等待,使用后释放锁即可,但是也可能存在以下问题:
      1. 一个线程持有锁会导致其他所有需要此锁的线程挂起;
      2. 在多线程竞争下,加锁、释放锁会导致比较多的 上下文切换 和 调度延时,引起性能问题;
      3. 如果一个优先级高的线程等待一个优先级低的线程释放锁 会导致优先级 倒置,引起性能问题。

    3. 三大不安全案例

    3.1 购票案例

    package com.baiyi.synchronize;
    
    /**
     * @author 白衣
     * @Description: 线程锁不安全案例一:  购票
     * @Date 2020/11/22
     */
    public class UnsafeBuyTicket {
        public static void main(String[] args) {
            BuyTicket station = new BuyTicket();
    
            new Thread(station, "苦逼的我").start();
            new Thread(station, "牛逼的你们").start();
            new Thread(station, "可恶的黄牛党").start();
        }
    }
    
    class BuyTicket implements Runnable {
        // 票
        private int ticketNum = 10;
        private boolean flag = true;
    
        @Override
        public void run() {
            // 买票
            while (flag) {
                try {
                    buy();
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        }
    
        private void buy() {
            // 判断是否有票
            if (ticketNum <= 0) {
                flag = false;
                return;
            }
            // 模拟延时
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 买票
            System.out.println(Thread.currentThread().getName() + "拿到了" + ticketNum-- + "票");
        }
    }
    
    - 结果
    牛逼的你们拿到了8票
    苦逼的我拿到了9票
    可恶的黄牛党拿到了10票
    牛逼的你们拿到了7票
    苦逼的我拿到了6票
    可恶的黄牛党拿到了5票
    苦逼的我拿到了4票
    可恶的黄牛党拿到了3票
    牛逼的你们拿到了2票
    苦逼的我拿到了1票
    可恶的黄牛党拿到了0票
    牛逼的你们拿到了-1票
    
    - 分析:线程不安全 出现了 -1 或者出现了 一张票被多个人抢到
    - 出现 -1 的原因分析:因为每个线程都在自己的工作内存交互,所以他们都看到了还有一张票可以抢,
    - 然后我抢了,票数为0,然后你们也看到还有一张,再抢,票数为 -1,然后就出现了 -1。
    

    3.2 取钱案例

    问题原型:一对夫妇的一张银行卡上有500万元,他们都想取钱,老公去了银行准备取钱,老婆在手机 App 上准备取钱,在这时候,他们都看到了账户上有 500 万,老公打算取 500 万,老婆打算取 300 万,然后他们同时进行取钱,最后发现账户为 -300 万。

    package com.baiyi.synchronize;
    
    /**
     * @author 白衣
     * @Description: 模拟银行取钱
     * @Date 2020/11/22
     */
    public class UnsafeBank {
        public static void main(String[] args) {
            Account account = new Account(100, "结婚基金");
            Thread you = new Thread(new Drawing(account, 50, "你"));
            Thread girlFriend = new Thread(new Drawing(account, 100, "girlFriend"));
    
            you.start();
            girlFriend.start();
        }
    }
    
    
    class Account{
        int money; // 账户余额
        String name; // 卡名称
    
        public Account(int money, String name) {
            this.money = money;
            this.name = name;
        }
    }
    
    class Drawing extends Thread{
        Account account;
        int drawingMoney;
        int nowMoney;
    
        /**
         * @Author 白衣
         * @Description 构造方法
         * @Date 2020/11/23
         * @param account 账户
         * @param drawingMoney 准备取出的金钱
         * @param name 谁取钱
         * @return
         */
        public Drawing(Account account, int drawingMoney, String name){
            super(name);
            this.account = account;
            this.drawingMoney = drawingMoney;
        }
    
        @Override
        public void run() {
            // 判断是否有钱
            if (account.money - drawingMoney < 0){
                System.out.println(Thread.currentThread().getName() + "钱不够,取不了");
                return;
            }
    
            // sleep 放大问题的发生性
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            // 卡内的钱 = 余额 - 取的钱
            account.money = account.money - drawingMoney;
            // 你手上的钱
            nowMoney = nowMoney + drawingMoney;
            System.out.println(account.name + "余额为:" + account.money);
            // this.getName = Thread.currentThread().getName()
            System.out.println(this.getName() + "手里的钱为:" + nowMoney);
        }
    }
    
    - 结果:
    结婚基金余额为:50
    你手里的钱为:50
    结婚基金余额为:-50
    girlFriend手里的钱为:100
    
    - 账户余额出现了负数
    

    3.3 线程不安全的集合

    package com.baiyi.synchronize;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author 白衣
     * @Description: 线程不安全的集合
     * @Date 2020/11/23
     */
    public class UnsafeList {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            for (int i = 0; i < 500000; i++) {
                new Thread(()->{
                    list.add(Thread.currentThread().getName());
                }).start();
            }
    
            System.out.println(list.size());
        }
    }
    
    - 结果
    499995  而不是 500000
    

    4. 同步方法

    • 由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:
      synchronized 方法: public synchronized void method(int args){}
      synchronized 块:

    • synchronized 方法控制 对象 的访问,每个对象对应一把锁,每个 synchronized 方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行。

    • 缺点:若将一个大的方法声明为 synchronized 将会影响效率

    • 如下图所示,方法里面需要修改的内容才需要锁,锁的太多,浪费资源,因此出现了 synchronized 代码块

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TzXmvRxj-1606113309480)(/Users/liaozicai/Documents/Java/Note/Basic/多线程/多线程.assets/image-20201123111919572.png)]

    package com.baiyi.synchronize;
    
    /**
     * @author 白衣
     * @Description: 线程锁不安全案例一:  购票
     * @Date 2020/11/22
     */
    public class UnsafeBuyTicket {
        public static void main(String[] args) {
            BuyTicket station = new BuyTicket();
    
            new Thread(station, "苦逼的我").start();
            new Thread(station, "牛逼的你们").start();
            new Thread(station, "可恶的黄牛党").start();
        }
    }
    
    class BuyTicket implements Runnable {
        // 票
        private int ticketNum = 10;
        private boolean flag = true;
    
        @Override
        public void run() {
            // 买票
            while (flag) {
                try {
                    buy();
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        }
    
        private synchronized void buy() {
            // 判断是否有票
            if (ticketNum <= 0) {
                flag = false;
                return;
            }
            // 模拟延时
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 买票
            System.out.println(Thread.currentThread().getName() + "拿到了" + ticketNum-- + "票");
        }
    }
    
    - 分析:
    	在购票中,只有唯一对象,不存在共享资源,因此只需要锁 方法 即可。
    

    5. 同步块

    • 同步块: synchronized(Obj) {}

    • Obj: 称之为 同步监视器

      1. Obj 可以是任何对象,但是推荐使用 共享资源 作为同步监视器
      2. 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是 this,就是这个对象本身,或者是 class
    • 同步监视器的执行过程:

      1. 第一个线程访问,锁定同步监视器,执行其中代码
      2. 第二个线程访问,发现同步监视器被锁定,无法访问
      3. 第一个线程访问完毕,解锁同步监视器
      4. 第二个线程访问,发现同步监视器没有锁。然后锁定并访问
    package com.baiyi.synchronize;
    
    /**
     * @author 白衣
     * @Description: 模拟银行取钱
     * @Date 2020/11/22
     */
    public class UnsafeBank {
        public static void main(String[] args) {
            Account account = new Account(1000, "结婚基金");
            Thread you = new Thread(new Drawing(account, 50, "你"));
            Thread girlFriend = new Thread(new Drawing(account, 100, "girlFriend"));
    
            you.start();
            girlFriend.start();
        }
    }
    
    
    class Account{
        int money; // 账户余额
        String name; // 卡名称
    
        public Account(int money, String name) {
            this.money = money;
            this.name = name;
        }
    }
    
    class Drawing extends Thread{
        Account account;
        int drawingMoney;
        int nowMoney;
    
        /**
         * @Author 白衣
         * @Description 构造方法
         * @Date 2020/11/23
         * @param account 账户
         * @param drawingMoney 准备取出的金钱
         * @param name 谁取钱
         * @return
         */
        public Drawing(Account account, int drawingMoney, String name){
            super(name);
            this.account = account;
            this.drawingMoney = drawingMoney;
        }
    
        @Override
        public void run() {
            synchronized (account){
                // 判断是否有钱
                if (account.money - drawingMoney < 0){
                    System.out.println(Thread.currentThread().getName() + "钱不够,取不了");
                    return;
                }
    
                // sleep 放大问题的发生性
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                // 卡内的钱 = 余额 - 取的钱
                account.money = account.money - drawingMoney;
                // 你手上的钱
                nowMoney = nowMoney + drawingMoney;
                System.out.println(account.name + "余额为:" + account.money);
                // this.getName = Thread.currentThread().getName()
                System.out.println(this.getName() + "手里的钱为:" + nowMoney);
            }
        }
    }
    

    6. 小结

    • 同步方法:synchronized 方法 —> public synchronized void method(int args){}
      锁住的 this 对象本身 ------ 单个对象操作一个资源时使用
    • 同步块:synchornized 块 —> synchronized (Obj){}
      锁住的是:同步操作的对象,也就是共享资源(变化的量,需要增删改查操作的) — 多个对象操作同一个资源时使用
    展开全文
  • 多线程高并发常见的面试题

    千次阅读 2021-08-10 19:10:49
    现在的系统动不动就要百万级甚至千万级的并发量,而多线程并发编程正是开发高并发系统的基础,利用好多线程极致可以大大提高系统整体的并发能力以及性能。面对复杂的业务模型,并行程序会比串行程序更适合业务需求,...
  • java 如何处理高并发编程的解决方案 视频资料齐全
  • 多线程高并发介绍

    万次阅读 多人点赞 2021-06-06 05:00:46
    多线程高并发介绍 文章目录多线程高并发介绍前言一、什么是多线程?1.多线程介绍2.多线程实现原理?3.白话文解释多线程4.多线程存在的问题二、什么是高并发?1.高并发介绍2.如何提升系统的并发能力三、多线程...
  • 多线程高并发整理总结【超全面】

    千次阅读 多人点赞 2020-11-22 10:37:30
    我们先说一下为什么要讲多线程高并发? 原因是,你想拿到一个更高的薪水,在面试的时候呈现出了两个方向的现象: 第一个上天 项目经验 高并发、缓存、大流量、大数据量的架构设计 第二个入地 各种基础算法,...
  • WEB API 多线程并发测试工具; WEB API 多线程并发测试工具
  • 假设你是大型电商互联网企业的架构师,基于kafka、zookeeper,多线程等技术、基于单台服务器,MQ生产方发送1千万个User对象,User对象包含id,name这两个属性。要求:实现以下两种技术功能:1、并发场景:消息生产方...
  • 详细介绍:多线程高并发

    千次阅读 2020-11-25 16:31:56
    分类专栏: Java进阶 文章标签: 高并发 多线程 高并发指标 高并发解决方案 一、什么是高并发 高并发(High Concurrency)是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况,主要发生在web系统...
  • Java面试——多线程高并发

    千次阅读 2021-10-24 16:52:23
    一个进程就是一个应用程序,系统会为该进程分配资源空间,当用户并发请求的时候,为每个用户创建一个进程资源开销太大难以实现,就开辟了线程线程速度比较快,线程之间共享进程之间的内存资源。 2、如何在Java中...
  • 05、【高级原理】【高级原理实战】Java并发编程与高并发解决方案(完整无密) 06、【深度进阶】【高级原理实战】java高级多线程高并发编程实战(三个阶段) 07、【高并发项目实战】多线程并发分布式并发项目实战 共74...
  • 多线程高并发编程MySQL数据库处理

    千次阅读 2020-08-10 17:51:44
    本文作者:陈进坚 ... 摘要 ​ 现在很多主流的编程语言都支持多线程或者协程处理,例如天生...但是多线程和单线程不同,多线程如果不对数据库做处理的话,有时候单线程跑的程序没有问题,但是一旦开启多线程,数据库就.
  • 多线程并发的一些解决思路

    千次阅读 2020-08-28 13:58:54
    一、利用不变性解决并发问题 不变性(Immutability)模式。所谓不变性,简单来讲,就是对象一旦被创建之后,状态就不再发生变化。换句话说,就是变量一旦被赋值,就不允许修改了(没有写操作);没有修改操作,也...
  • 多线程高并发的区别

    千次阅读 2019-05-29 11:20:09
    多线程是完成任务的一种方法高并发是系统运行的一种状态,通过多线程有助于系统承受高并发的状态的实现。 高并发是系统运行过程张遇到的一种“短时间内遇到大量的操作请求” 的情况,主要发生在web系统集中大量...
  • 在.NET的世界里面,处理高并发大致有以下几种方法: 1、异步编程 异步编程就是使用future模式(又称promise)或者回调机制来实现(Non-blocking on waiting)。如果使用回调或事件来实现(容易callback hell),不仅...
  • 多线程高并发的常见面试题整理

    千次阅读 2020-07-12 11:46:03
    定义Thread类的子类,并重写Thread类的run()方法,创建子类对象(即线程对象),调用线程对象的start()方法来启动该线程 2.实现Runnable接口 并重写该接口的run()方法,该run()方法同样是该线程的执行体。创建该...
  • Java中的多线程高并发

    千次阅读 2021-11-22 17:20:53
    线程是系统调度的最小单元,是线程的运算单元,一个进程可以包括一个或线程线程的三种创建方式: 一、继承Thread类 class MyThread extends Thread { @Override public void run() { Log.i(TAG, ...
  • 1.ArrayList的线程不安全解决方案 将main方法的第一行注释打开,执行几次,会看到如下图这样的异常信息:???????????? 这是一个 并发修改 异常,首先ArrayList肯定是线程不安全的,产生这个异常的原因就是...
  • 多线程高并发解决办法

    万次阅读 2015-05-03 13:28:51
    1 線程間的代碼併做好同步工作,防止鎖的氾濫2 用線程池,解决多线程高并发3还有使用异步的方法3.1异步就是解决多线程高并发的。多个操作可以投递到一个线程或几个线程上完成。Windows下的异步操作典型是IOCP(完成...
  • JavaWeb 并发编程 与 高并发解决方案

    万次阅读 多人点赞 2018-09-12 03:41:00
    在这里写写我学习到和自己所理解的 Java高并发编程和高并发解决方案。现在在各大互联网公司中,随着日益增长的互联网服务需求,高并发处理已经是一个非常常见的问题,在这篇文章里面我们重点讨论两个方面的问题,一...
  • 高并发请求下,服务器替换创建线程高并发请求下,数据库连接池中的连接数有限。 高并发请求下,点赞功能是同步处理等。 解决方法: 初步 我们通过约会Redis缓存避免高并发写数据库而造成数据库压力,同时约会...
  • java高并发解决方案

    千次阅读 2021-09-01 16:04:29
    高并发解决思路与手段 扩容:水平扩容、垂直扩容 缓存:Redis、Memcache、GuavaCache等 队列:Kafka、RabitMQ、RocketMQ等 应用拆分:服务化Dubbo与微服务Spring Cloud 限流:Guava RateLimiter使用、常用限流算法、...
  • JAVA多线程高并发的处理经验

    万次阅读 多人点赞 2019-02-24 17:36:59
    java中的线程:java中,每个线程都有一个调用栈存放在线程栈之中,一个java应用总是从main()函数开始运行,被称为主线程。一旦创建一个新的线程,就会产生一个线程栈。线程总体分为:用户线程和守护线程,当所有...
  • 多线程的理解 什么是多线程 如果一个程序允许两个或者两个以上的线程,那么它便是多线程程序。多线程是指单个进程内允许多个线程。 任务分为资源独立任务和资源共享任务。独立任务不需要使用多线程;共享任务,会...
  • 一、什么是高并发        高并发(High Concurrency)是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况,主要发生在web系统集中大量访问收到大量请求(例如:12306的抢票...
  • 单线程-多线程-高并发

    千次阅读 2019-02-13 16:27:48
    什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。 而一个进程又是由个...之前我将高并发解决方法误认为是线程或者是队列可以解决,因为高并发的时...
  • 多线程高并发编程之基础知识(上)

    万次阅读 多人点赞 2018-10-01 21:48:25
    使用多线程,第一步就是需要知道如何实现自定义线程,因为实际开发中,需要线程完成的任务是不同的,所以我们需要根据线程任务来自定义线程,那么,JDK提供了三种自定义线程的方式,供我们实际开发中使用,来开发出...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 313,241
精华内容 125,296
关键字:

多线程高并发怎么解决方案