线程同步与死锁

8.线程同步与死锁
1.线程同步产生原因

同步是指多个多线程访问统一资源所需要考虑到的问题。

public class TestSleep  implements Runnable{
    private int money=5;
    @Override
    public void run() {
        for(int i=0;i<10;i++){
           if(money>0) {
               try {
                   Thread.sleep(100);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println("购物" + Thread.currentThread().getName() + ":money = " + money--);
           }
        }
    }
}
class MySleep{
    public static void main(String[] args) {
        TestSleep testSleep = new TestSleep();
        Thread t1 = new Thread(testSleep,"A");
        Thread t2 = new Thread(testSleep,"B");
        Thread t3 = new Thread(testSleep,"C");
        t1.start();
        t2.start();
        t3.start();
    }
}

运行结果如下

购物B:money = 3
购物A:money = 4
购物C:money = 5
购物B:money = 2
购物A:money = 2
购物C:money = 2
购物B:money = 1
购物A:money = -1
购物C:money = 0

此次执行过后发现操作的结果出现了问题,这就叫做不同步的情况,这是怎么造成的?

消费的整个步骤分为两步:

1)判断是否还有钱

2)消费钱减少

2.线程同步处理操作

线程不同步的最大问题是:判断和修改数据是分开完成的,即某几个线程可以同时执行。

解决方法:必须使用同步,所谓的同步就是值多个线程在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行。

​ java里如果要实现线程的同步可以使用synchronized关键字。而这个关键字有两种使用方式:
1)一种是同步代码块

​ 2)另一种是同步方法

​ java中里面有四种代码块:普通代码块、构造块、静态块(static开头)、同步块(需要锁住一个对象)。

用同步块解决不同步问题:修改run方法代码如下:

 @Override
    public void run() {
        for(int i=0;i<10;i++){
            synchronized (this) {//当前操作每次只允许一个对象进入(锁住当前运行对象)
                if (money > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("购物" + Thread.currentThread().getName() + ":money = " + money--);
                }
            }
        }
    }

此次运行结果如下

购物A:money = 5
购物A:money = 4
购物A:money = 3
购物A:money = 2
购物A:money = 1

使用同步方法解决不同步问题代码如下:1)编写一个有synchronized修饰的方法,2)在run中调用同步方法

public class TestSleep  implements Runnable{
    private int money=5;
    @Override
    public void run() {
        buy();
    }
    public synchronized void buy(){ //synchronized 修饰的方法就是同步方法每次只能一个对象调用
        for(int i=0;i<10;i++){
            if (money > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("购物" + Thread.currentThread().getName() + ":money = " + money--);
            }
        }
    }
}

异步和同步相比,异步操作的执行速度要高于同步操作,但是同步操作时安全性高,属于线程安全的线程操作。

3.死锁

同步操作时一个线程对象等待另一个线程对象执行完毕的操作形式。线程同步过多就有可能造成死锁。

下面的例子:说明死锁的情况

class A{
    public synchronized void say(B b){
        System.out.println("我说:给我钱,我给你东西!");
        b.get();
    }
    public synchronized  void get(){
        System.out.println("我:得到了钱,付出了东西");
    }
}
class B{
    public synchronized void say(A a){
        System.out.println("你说:给我东西,我给你钱!");
        a.get();
    }
    public synchronized  void get(){
        System.out.println("你:得到了东西,付出了钱");
    }
}

public class TestSynchronized  implements Runnable{
    private static A a= new A();
    private static B b= new B();

    public static void main(String[] args) {
        new TestSynchronized();
    }

    public TestSynchronized(){
        new Thread(this).start();
        b.say(a);
    }
    @Override
    public void run() {
        a.say(b);
    }
}

以上的代码是死锁一个简单的例子,没有参考意义;死锁是程序上某种逻辑上的错我所造成的的问题,并不是简单的就会出现的。

面试题:请解释多个线程访问同一资源时需要考虑到那些情况?有可能带来那些问题?

1)多个线程访问统一资源一定要处理好同步,可以使用同步代码(synchronized(锁定对象){})块和同步方法(用synchronized修饰方法)

2)过多使用同步,有可能造成死锁。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苹水相峰

你的打赏是对我最大的肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值