线程的同步和synchronized关键字

线程同步

1、关于多线程并发环境下,数据的安全问题是重点。

在实际开发中,项目都是运行在服务器当中,而服务器已经将线程的定义,线程对象的创建,线程的启动等,都已经实现。这些代码我们都不需要编写。

最重要的是:程序需要放到一个多线程的环境下运行,更需要关注的是这些数据在多线程并发的环境下是否是安全的

2、满足以下3个条件,就会存在线程安全问题。

  • 条件1:多线程并发。
  • 条件2:有共享数据。
  • 条件3:共享数据有修改的行为。
  • 用排队执行解决线程安全问题。这种机制被称为:线程同步机制。实际上就是线程不能并发了,线程必须排队执行。

  • 线程排队会牺牲一部分效率,但数据安全是第一位,只有数据安全,才可以谈效率。

异步编程模型:多个线程各自执行各自的,谁也不需要等谁,这种编程模型叫做:异步编程模型。其实就是:多线程并发(效率较高。)

同步编程模型:多个线程不能同时进行,必须等待一个线程结束,另一个线程才能执行。两个线程之间发生了等待关系,其实就是:排队执行(效率较低)。

Synchronized关键字

1、Java中三大变量:实例变量(在堆中)、静态变量(在方法区)、局部变量(在栈中)。

  • 局部变量和常量永远不会有线程安全问题。
  • 成员变量:可能会有线程安全问题。

2、线程同步机制的语法是:

  • 第一种:
            synchronized(多个线程共享的){
                // 线程同步代码块。
            }

synchronized后面小括号中传的这个数据必须是多线程共享的数据。才能达到多线程排队。

需要找对象锁,一个对象只有一把锁。每个对象都有自己的锁。

/*取钱的方法*/
public void Withdraw(double money) {

    synchronized (this) {

        /*读取当前余额*/
        double before = getBalance();

        /*取钱*/
        double after = getBalance() - money;

        /*模拟网络延迟*/
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        /*取钱后修改当前余额*/
        setBalance(after);
    }
}
  • 第二种:Synchronized 出现在实例方法中

synchronized出现在实例方法上,一定锁的是this。只能是this,不能是其他的对象了。所以这种方式不灵活。

另外还有一个缺点:synchronized出现在实例方法上,表示同步整个方法体,可能会无故扩大同步的范围,导致程序的执行效率降低。所以这种方式不通用。

使用场景:如果共享的对象就是this,并且需要同步的代码块是整个方法体,建议使用这种方式。

/*取钱的方法*/
public synchronized void Withdraw(double money) {

        /*读取当前余额*/
        double before = getBalance();

        /*取钱*/
        double after = getBalance() - money;

        /*模拟网络延迟*/
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        /*取钱后修改当前余额*/
        setBalance(after);
}
  • 第三种:在静态方法上使用synchronized

需要找类锁。类锁永远只有1把,即使创建了100个对象,类锁也只有一把。

public synchronized  static void Withdraw(double money) {
}

3、死锁

synchronized在开发中最好不要嵌套使用,容易发生死锁现象。

在这里插入图片描述

public class DeadLockTest {
    public static void main(String[] args) {
        /*创建Object对象*/
        Object o1 = new Object();
        Object o2 = new Object();
        /*创建线程对象*/
        MyThread01 t1 = new MyThread01(o1,o2);
        MyThread01 t2 = new MyThread01(o1,o2);
        /*启动线程*/
        t1.start();
        t2.start();
    }
}
class MyThread01 extends Thread {
    Object o1;
    Object o2;

    public MyThread01(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }

    @Override
    public void run() {
        synchronized (o1){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o2) {

            }
        }
    }
}
class MyThread02 extends Thread {

    Object o1;
    Object o2;

    public MyThread02(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    @Override
    public void run() {
        synchronized (o2){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o1) {
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值