其他分享
首页 > 其他分享> > 2022-08-03 第4组 蒋萍 关于线程安全

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

作者:互联网

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

目录

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充当同步锁

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

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、常见的方法

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