zoukankan      html  css  js  c++  java
  • Java线程同步详解

    一、多线程运行问题

    1、各个线程是通过竞争CPU时间而获得运行机会的
    2、各线程什么时候得到CPU时间,占用多久,是不可预测的
    3、一个正在运行着的线程在什么地方被暂停是不确定的

    二、线程同步

    为了解决上述问题,确保共享对象在同一时间只允许被一个线程访问,即线程同步,可以使用synchronized和lock来实现。

    三、synchronized的使用方式

    1、修饰一个代码块,被修饰的代码块称为同步代码块,作用范围是大括号{}括起来的代码;
    2、修饰一个方法,被修饰的方法称为同步方法,其作用范围是整个方法;
    3、修饰一个静态方法,作用范围是整个静态方法;

    例程(银行存取款)

    Class Bank

    package com.imooc.bank;
    
    public class Bank {
        private String account;//账号
        private int balance;//账户余额
    
        public Bank(String account,int balane){
            this.account=account;
            this.balance=balane;
        }
    
        public String getAccount() {
            return account;
        }
    
        public void setAccount(String account) {
            this.account = account;
        }
    
        public int getBalance() {
            return balance;
        }
    
        public void setBalance(int balance) {
            this.balance = balance;
        }
    
        @Override
        public String toString() {
            return "Bank[账号:"+account+",余额:"+balance+"]";
        }
        //存款
        public synchronized void saveAccount(){
            //获取当前的账户余额
            int balance=getBalance();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //修改金额,存100元
            balance+=100;
            //修改账余额
            setBalance(balance);
            //输出存款后的账户余额
            System.out.println("存款后的账户余额为:"+balance);
        }
        public void drawAccount(){
            synchronized (this){
                //获得当前账户余额
                int balance=getBalance();
                balance=balance-200;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                setBalance(balance);
                System.out.println("取款后的账户余额:"+balance);
            }
        }
    }
    
    

    Class DrawAccount 取款

    package com.imooc.bank;
    
    public class DrawAccount implements Runnable{
        Bank bank;
        public DrawAccount(Bank bank){
            this.bank=bank;
        }
        @Override
        public void run() {
            bank.drawAccount();
        }
    }
    
    

    Class SaveAccount 存款

    package com.imooc.bank;
    
    public class SaveAccount implements Runnable{
    
        Bank bank;
        public SaveAccount(Bank bank){
            this.bank=bank;
        }
        @Override
        public void run() {
            bank.saveAccount();
        }
    }
    
    

    Class Test 测试类

    package com.imooc.bank;
    
    public class Test {
        public static void main(String[] args) {
            //创建账户,给定余额为10000
            Bank bank=new Bank("1001",1000);
            //创建线程对象
            SaveAccount sa=new SaveAccount(bank);
            DrawAccount da=new DrawAccount(bank);
            Thread save=new Thread(sa);
            Thread draw=new Thread(da);
            save.start();
            draw.start();
            try {
                draw.join();
                save.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(bank);
        }
    }
    
    

    经过测试,当不加入synchronized实现线程同步时,存款取款的账户余额会发生错误,
    这里使用线程延时模拟了线程被打断的情况,当存款没完全进行完时打断了此线程进行取款
    此时取款后的余额不正确。

    当加入了线程同步后,此问题得到了解决。

    lock的使用方式

    1、synchroized同步的时候,其中一条线程用完会自动释放锁,而Lock需要手动释放,如果不手动释放,可能造成死锁
    2、使用synchronized如果其中一个线程不释放锁,那么其他需要获取锁的线程会一直等待下取,直到使用完释放或者出现异常,
    而Lock可以使用响应中断或者使用规定等待时间的锁
    3、synchronized无法得知是否获取到锁,而Lock可以做到
    4、用ReadWriteLock可以提高多个线程进行读操作的笑了

    lock简单的使用方法

    //创建lock对象
    Lock lock=new ReentrantLock();
    //手动加锁
    lock.lock();
     try{
        // 处理
     }catch(Exception ex){
         // 捕获异常
    }finally{
         // 释放锁
         lock.unlock();   
     }
    
    
    你以为的极限,也许只是别人的起点
  • 相关阅读:
    第三套三
    多线程读写共享变量时,synchronized与volatile的作用
    jQuery源代码学习笔记:构造jQuery对象
    写入位置时发生訪问冲突
    Free Editor
    大区间素数筛选 POJ2689
    HDU
    CentOS下挂载U盘
    得到当前堆栈信息的两种方式(Thread和Throwable)的纠结
    [实战]MVC5+EF6+MySql企业网盘实战(9)——编辑文件名
  • 原文地址:https://www.cnblogs.com/LengDing/p/15115001.html
Copyright © 2011-2022 走看看