线程同步,JUC并发

线程同步

多个线程操作同一个资源。

并发:同一个对象被多个线程同时操作。

  • 由于同一进程的多个线程共享同一块存储空间,带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可,存在以下问题:

    • 一个线程持有锁会导致其他所有需要此锁的线程挂起;

    • 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题。

    • 如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题。

三个不安全示例

不安全买票的测试代码:

复制代码
//不安全的买票
//线程不安全,数字有被同时拿到,会变成负数
public class UnsafeBuyTicket {
​
    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();
​
​
        new Thread(station,"i").start();
        new Thread(station,"you").start();
        new Thread(station,"it").start();
​
    }
​
}
​
class BuyTicket implements Runnable{
​
    //
    private int ticketNums = 10;
    boolean flag = true; //外部停止方式
​
    @Override
    public void run() {
        //买票
        while (flag){
            buy();
        }
    }
​
    private void buy(){
        //判断是否有票
        if(ticketNums<=0){
            flag = false;
            return;
        }
​
        //模拟延时
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
​
        //买票
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}
复制代码

 

不安全取钱的测试代码:

复制代码
//不安全的取钱
public class UnsafeBank {
​
​
    public static void main(String[] args) {
        //账户
        Account account = new Account(100,"基金");
​
        Drawing you = new Drawing(account,50,"你");
        Drawing girl = new Drawing(account,100,"girl");
​
        you.start();
        girl.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;
​
    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);
        //Thread.currentThread().getName() = this.getName()
        System.out.println(this.getName()+"手里的钱:"+nowMoney);
    }
}
复制代码

 

线程不安全的集合:

复制代码
//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
复制代码

 

同步方法及同步块

  • synchronized关键字,包括两种用法synchronized方法和synchronized块。

  • 方法前面加synchronized,必须获得锁才能执行,否则线程会阻塞。

    • 若将一个大的方法申明为synchronized会影响效率。

同步块:

  • 同步块:synchronized(Obj){}

改进不安全买票的测试代码:

复制代码
public class UnsafeBuyTicket {
​
    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();
​
​
        new Thread(station,"it").start();
        new Thread(station,"i").start();
        new Thread(station,"you").start();
​
​
​
    }
​
}
​
class BuyTicket implements Runnable{
​
    //
    private int ticketNums = 10;
    boolean flag = true; //外部停止方式
​
    @Override
    public void run() {
        //买票
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
​
    //synchronized 同步方法,锁的是this
    private synchronized void buy() throws InterruptedException {
        //判断是否有票
        if(ticketNums<=0){
            flag = false;
            return;
        }
​
        //模拟延时
​
        Thread.sleep(100);
​
​
        //买票
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}
复制代码

 

改进不安全取钱测试代码:

复制代码
public class UnsafeBank {
​
​
    public static void main(String[] args) {
        //账户
        Account account = new Account(1000,"基金");
​
        Drawing you = new Drawing(account,50,"你");
        Drawing girl = new Drawing(account,100,"girl");
​
        you.start();
        girl.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;
​
    public Drawing(Account account,int drawingMoney,String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }
​
    //取钱
    //synchronized:默认锁的是this
    @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);
            //Thread.currentThread().getName() = this.getName()
            System.out.println(this.getName()+"手里的钱:"+nowMoney);
​
        }
​
​
    }
}
复制代码

 

改进不安全集合测试代码:

复制代码
//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
​
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
​
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
复制代码

 

JUC并发包:

测试代码:

复制代码
//测试JUC安全类型的集合
public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
复制代码

 

 
posted @   Resign~as  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示