线程 synchroized

线程 synchroized

synchroized 同步方法

由于我们可以通过 private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提岀一套机制,这套机制就是 synchronized 关键字。它包括两种用法 synchronized方法和 synchronized 块。

同步方法

public synchronized void method (int args) {

}

synchronized 方法控制对 “对象" 的访问。

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

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

package com.gcbeen.thread;

// 安全买票
public class TestSafeBuyTicket {
    public static void main(String[] args) {
        SafeBuyTicket buyTicket = new SafeBuyTicket();
        new Thread(buyTicket, "张三").start();
        new Thread(buyTicket, "李四").start();
        new Thread(buyTicket, "王五").start();
    }
}


class SafeBuyTicket implements Runnable {
    // 票
    private int ticketNums = 10;
    boolean flag = true;

    @Override
    public void run() {
        // 买票
        while (flag) {
            try {
                buy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // synchronized 同步方法
    // 买票
    private synchronized void buy() {
        // 判断是否有票
        if (ticketNums <= 0) {
            flag = false;
            return;
        }
        // 延迟
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 买票
        System.out.println(Thread.currentThread().getName()
                + "拿到" + ticketNums--);
    }
}


// 张三拿到10
// 张三拿到9
// 张三拿到8
// 张三拿到7
// 张三拿到6
// 张三拿到5
// 张三拿到4
// 张三拿到3
// 张三拿到2
// 王五拿到1

synchroized 同步块

同步块

synchronized (Obj) {

}

obj称之为同步监视器

Obj可以是任何对象,但是推存使用共享资源作为同步监视器。

同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class。

同步监视器的执行过程

  1. 第一个线程访问,锁定同步监视器,执行其中代码;

  2. 第二个线程访问,发现同步监视器被锁定,无法访问;

  3. 第一个线程访问完毕,解锁同步监视器;

  4. 第二个线程访问,发现同步监视器没有锁,然后锁定并访问。

锁的对象就是变量,需要增删改查的对象

安全的取钱

package com.gcbeen.thread;

// 安全的取钱 同步块
public class TestSafeBank {

    public static void main(String[] args) {
        SafeAccount account = new SafeAccount(100, "养老基金");
        SafeDrawing drawing = new SafeDrawing(account, 60, "夸克");
        SafeDrawing same = new SafeDrawing(account, 60, "same");
        drawing.start();
        same.start();
    }

}


class SafeAccount {
    int money;  // 余额
    String cardName;    // 卡名

    public SafeAccount(int money, String cardName) {
        this.money = money;
        this.cardName = cardName;
    }
}

class SafeDrawing extends Thread {
    SafeAccount account;    // 账户
    int drawingMoney;   // 取余额
    int nowMoney;   // 个人手里的钱

    public SafeDrawing(SafeAccount account, int drawingMoney, String name) {
        // super(name) =  父类构造方法(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;
            }
            try {
                Thread.sleep(1000); // 放大问题的发生性
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 卡内金额 = 余额 - 个人手里的钱
            account.money = account.money - drawingMoney;
            // 个人手里的钱
            nowMoney = nowMoney + drawingMoney;
            System.out.println(account.cardName + "余额为:" + account.money);
            // this.getName()==Thread.currentThread().getName()
            System.out.println(this.getName() + "手里的钱:" + nowMoney);
        }
    }
}

// 养老基金余额为:40
// 夸克手里的钱:60
// same余额不足,不能进行取钱

方法里面需要操作共享资源的代码才需要加锁。锁太多浪费资源

线程安全的集合

package com.gcbeen.thread;

import java.util.ArrayList;
import java.util.List;

// 线程安全的集合 同步块
public class TestSafeList {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int k = 0; k < 3; k++) {
            new Thread(() -> {
                for (int i = 0; i < 10000; i++) {
                    synchronized (list) {
                        list.add(Thread.currentThread().getName());
                    }
                }
            }).start();
        }

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }

}
// 30000
posted @   gcbeen  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示