ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022-08-03 第4组 蒋萍 关于线程安全

2022-08-03 22:31:57  阅读:197  来源: 互联网

标签:03 同步 synchronized Thread 08 蒋萍 线程 监视器 wait


哐当哐当,呼呼呼,啊,我脑子里都是水呀。

目录

1、线程安全(重点,面)

当某一线程尚未完成,其他线程也插入运行时,可能会出现线程安全问题,有没有线程安全问题取决于有没有共享数据,

怎么解决:(上厕所把门锁好)

当一个线程完成工作时,其他线程不准插入进来,直到线程完成它的工作,其他线程才能继续执行

在Java中,通过同步机制来解决线程安全问题

1.1 方式一:同步代码块

1.1.1 处理实现Runnable接口方式的线程安全问题

synchronized(同步监视器){
    
    // 需要被同步的代码:操作共享数据的代码,或理解为多个线程共同操作的变量  
}

同步监视器是啥 ???

就是所说的;任何类的对象都可以充当锁;而且,多个线程必须要共用同一把锁

同步方式解决了线程安全问题,但是操作同步代码时只能由一个线程操作,其他线程等待,相当于单线程操作,效率低一些。

同步监视器可以考虑用this

1.1.2 处理继承Thread类方式的线程安全问题

对象造多了的时候,注意:多个线程必须要共用同一把锁可以:

public static Object obj = new Object();

或者:( 慎用 ), 注意对象

 // 直接用当前唯一对象(看谁在调run())就可以
synchronized(this){  // 注意:是唯一对象,当这个类造了多个对象时就不可以这样了~~~
    
    // 需要被同步的代码
}
    

或者:类做对象

// 类也是对象;类只会被加载一次
synchronized(当前类名.class){
    
    // 需要被同步的代码
}

1.2 方式二:同步方法

1.2.1 处理实现Runnable接口方式线程安全问题

如果操作共享的数据的代码块都完整声明在同一方法中,我们可以考虑把此方法声明为同步的。

然后在run()中调用这个方法即可

例如:

private synchronized void method(){  // 此时同步监视器为 this
    // 共享操作
}
public void run(){
    while(true){        
         method();
    }
}

1.2.1 处理继承Thread类方式线程安全问题

static

private static synchronized void method(){  // 此时同步监视器不是this,此时为当``前类,类是唯一的~
    // 共享操作
}
public void run(){
    while(true){        
         method();
    }
}

1.2.2 同步方法总结

  • 同步方法也涉及了同步监视器,只是不需要我们显式声明;

  • 非静态的同步方法,同步监视器是this,即当前对象

  • 静态的同步方法,同步监视器是当前类本身

  • 同步代码块:

​ 选好同步监视器,推荐用类对象,第三方对象,this

​ 在实现接口创建线程类中,同步代码块不可用this充当同步锁

同步的方式,解决线程安全问题,操作同步代码时,只有一个线程可以参与,其他线程等待,相当于一个单线程过程,效率低。

synchronized只针对当前JVM可解决线程安全问题,不可跨JVM解决问题。

1.2.3 使用同步机制将单例模式中的懒汉式改写为线程安全的

单例模式:只能创建一个当前对象实例

public class BankTest{
}
class Bank{
    private bank(){}
    private static Bank instance = null;
    public static Bank getInstanece(){
        /*后一批线程来者发现instance已经不是null了,所以就不用干等了,直接出去即可*/
        if (instance == null){ 
            // 先一批线程都进来
            synchronized(Bank.class){ // 谁抢到了资源先进入了
                if (instance == null){
                    instance = new Bank();
                }
            }
        }
        return instance; // 线程完成任务
    }
}

1.3 线程死锁问题

死锁:线程之间相互等待对方放弃自己所需的同步资源 (狭路相逢,就不给对方让道)

此时不会出现异常,只是所有线程都是阻塞状态

//死锁
public class Wait  {

    private  static  Object obj1=new Object();
    private  static  Object obj2=new Object();

    private  static void StartThread1(){
        Thread t1 = new Thread() {
            @Override
            public void run() {
                synchronized (obj1) {
                    try {
                        Thread.sleep(1000);
                        System.out.println("1线程obj1");
                    } catch (InterruptedException exp) {
                        exp.printStackTrace();
                    }
                    synchronized (obj2) {
                         System.out.println("1线程obj2");
                    }
                } 
            }
        };
        t1.start();
    }
    private  static void StartThread2(){
        Thread t2=new Thread() {
            @Override
            public void run() {
                synchronized (obj2) {
                    try {
                        Thread.sleep(1000);
                        System.out.println("2线程obj2");
                    } catch (InterruptedException exp) {
                    }
                    synchronized (obj1) {
                        System.out.println("2线程obj1");
                    }
                }
            }
        };
        t2.start();
    }

    public static void main(String[] args) {
        StartThread1();
        StartThread2();
        System.out.println("运行完成");
    }
}

都等着某个资源的释放,

Java死锁产生:

1、互斥使用,当资源被一个线程占用,别的线程不能使用

2、不可抢占,资源请求者不可强制从占有者中抢夺资源,只能占有者主动释放

3、请求和保持

4、循环等待,存在等待队列

要会代码实现

解决:专门的算法、原则;尽量少同步资源;尽量避免嵌套同步

2、线程通信

就理解为多个线程的使用,
image

3、常见的方法

  • 以下方法一定是出现在同步代码块/同步方法中

  • 且这三个方法的调用者必须是同步代码块/同步方法中的同步监视器,否则报错IllegalMonitorStateException

  • 这三个方法不是定义在Thread类中的,它们是定义在java.lang.Object类中

    同步监视器可以由任意对象充当,

wait(); // 线程进入阻塞状态,并释放同步监视器—— > 在同步代码块或同步方法中用

notify(); // 唤醒被wait的一个线程,如果多个线程被wait,就先唤醒优先级高的那个

notifyAll(); // 唤醒被wait的全部线程

4、sleep() 和 wait()异同(面)

同:只要执行这两个方法,都可以让当前线程进入阻塞状态

异:

1、位置:Thead类中声明sleep(),Object类中声明wait(),所以要用wait() 就要实例化 Object ;

2、调用要求:sleep()需要就调,wait() 只出现在同步代码块/同步方法中

3、是否释放同步监视器:如果两方法都使用在同步代码块/同步方法中,sleep()不会释放,而wait()会释放

4、sleep()限时自醒,wait() 要用notify() 触发唤醒
5、 sleep() 释放CPU资源,但不会释放锁
wait() 释放CPU资源,也会释放锁

经典例题:生产者与消费问题:

分析:

  1. 是否是多线程问题?
  2. 是否有共享数据?
  3. 怎么解决线程安全问题?
  4. 是否涉及线程通信?

标签:03,同步,synchronized,Thread,08,蒋萍,线程,监视器,wait
来源: https://www.cnblogs.com/fulfill/p/16548951.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有