多线程复习二

1、线程安全问题产生的原因

  • 多线程共享同一资源
  • cpu对线程的调度,使得每个线程在就绪、阻塞、运行之间随意切换

比如两个线程同时处于运行状态对同一资源进行操作

2、解决线程安全问题

  • 同步代码块(Synchronized
  • 同步方法

1、Synchronized代码块

Synchronized(同步监视器){
	//需要被的同步代码
}

同步代码:操作共享数据的代码。(对数据进行增、删、改)

同步监视器:又称为锁,任何一个类的对象都可以充当锁。(多个线程共用一把锁,即一个对象)

2、Synchronized同步方法

 public synchronized void run() {
       //需要被同步的方法
 }

在非静态同步方法中,同步监视器是 this
在静态同步方法中,同步监视器是该类的class对象(反射)
所以可以同时调用实例同步方法和静态同步方法,因为它们的锁不是同一个。

3、显式同步锁Lock

Lock是接口,ReentrantLock是它的实现类,比较常用

  1. 创建ReentrantLock实例
  2. 调用lock(),为当前对象上锁
  3. 最后调用unlock(),为当前对象解锁
class Task implements Runnable{

    private ReentrantLock lock = new ReentrantLock();
    private int ticket = 100;

    @Override
    public void run() {
            try{
                while (ticket > 0) {
                    lock.lock();
                    System.out.println(ticket--);
                }
            }finally {
                lock.unlock();
            }
    }
}

4、Synchronized与Lock的区别

  1. Synchronized是隐式锁,进入作用域自动上锁,结束自动释放锁。Lock是显式锁,必须手动上锁与解锁
  2. Lock只有代码锁,Synchronized有代码锁与方法锁
  3. Lock有更好的扩展性,并且jvm可以花费较少的时间来调度线程,性能更好

5、总结

  1. 同步方法与代码块,使得线程安全得以解决,但是降低了程序运行速度。当运行到同步代码块或同步方法时,只有一个线程可以操作代码,其他线程等待,相当于单线程
  2. 使用Synchronized时,注意使用的范围,不能过大也不能过小
  3. 一个对象拥有一个锁,所以无法同时调用两个静态同步方法或非静态同步方法
  4. 解决多线程的安全问题,只要使多线程共享一个锁

3、死锁

1、什么是死锁

不同线程分别占用了对方需要的同步资源不放弃,都等待对方放弃自己所需同步资源,这样就形成了死锁。

从生命周期的角度来说,就是多个线程都进入了阻塞状态,且无法退出阻塞,导致程序无法继续运行。

例子

public static void main(String[] args){
        Object obj1 = new Object();
        Object obj2 = new Object();

        Thread thread = new Thread(){
           @Override
           public void run() {
               synchronized (obj1){
                   System.out.println(Thread.currentThread().getName()+"获得obj1");
                   synchronized (obj2){
                       System.out.println(Thread.currentThread().getName()+"获得obj2");
                   }
               }
           }
       };

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj2){
                    System.out.println(Thread.currentThread().getName()+"获得obj2");
                    synchronized (obj1){
                        System.out.println(Thread.currentThread().getName()+"获得obj1");
                    }
                }
            }
        });

        thread.start();
        thread1.start();
    }

2、如何避免死锁

  • 尽量避免嵌套同步
  • 尽量减少同步资源的定义
  • 采取专门的算法

4、线程通信

1、线程通信方法

  • wait():一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器
  • notify():一旦执行此方法,就会唤醒被wait()的一个线程,有多个线程就唤醒优先级高的
  • notifyAll():一旦执行此方法,就会唤醒被wait()的所有线程

PS:

  1. 三个方法必须使用在同步代码块或同步方法中(Synchronized)
  2. 这三个方法的调用者必须是同步方法或同步代码块中的同步监视器;否则会出现 IllegalMonitorStateException异常
  3. 这三个方法定义在Object对象中,因为任何对象都可以充当同步监视器
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值