Três métodos para resolver problemas de segurança de thread em Java: bloco de código de sincronização, método de sincronização, bloqueio


Prefácio

Primeiro usamos o conhecimento adquirido de multi-threading para simular o processo de venda de ingressos de cinema, levando a problemas de segurança de thread.

 /*
    需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口
    请设计一个程序模拟该电影院售票过程。
    使用Thread类实现
    分析:   1.三个窗口相当于三个线程
            2.100张票属于共享资源
     */
  • Código 1: implementação do método 1 de implementação multi-threaded
public class 案例演示1 {
    
    
    public static void main(String[] args) {
    
    
        CellThread th1 = new CellThread("窗口1");
        CellThread th2 = new CellThread("窗口2");
        CellThread th3 = new CellThread("窗口3");
        th1.start();
        th2.start();
        th3.start();
    }
}
class CellThread extends Thread{
    
    
    //设置票为静态变量,即共享资源
    static int piao = 100;
    //提供无参构造
    public CellThread() {
    
    
    }
    //创建有参构造,不再调用setName()方法给线程起名字
    public CellThread(String name) {
    
    
        super(name);
    }

    @Override
    public void run() {
    
    
        while (true){
    
    
            if(piao>0){
    
    
                System.out.println(Thread.currentThread().getName()+"正在售卖"+(piao--)+"张票");
            }
        }
    }
}
  • Código 2: Implementação usando o método 2 de multithreading
public class 案例演示2 {
    
    
    public static void main(String[] args) {
    
    
        Myrunable myrunable = new Myrunable();
        //我们只创建了一个任务,所以是共同售卖100张票。
        Thread th1 = new Thread(myrunable, "窗口1");
        Thread th2 = new Thread(myrunable, "窗口2");
        Thread th3 = new Thread(myrunable, "窗口3");
        th1.start();
        th2.start();
        th3.start();
    }
}
class Myrunable implements Runnable{
    
    
    static int piao=1000;
    @Override
    public void run() {
    
    
        while (true) {
    
    
            if (piao > 0) {
    
    
                //模拟了一下网络延迟,发现出现不合理的数据,即出现了线程安全问题。
                //1.出现了0票和负数票,是因为线程并发执行导致的
                //2,出现了重复票,是因为原子性所导致的。(自行科普)
                try {
    
    
                    Thread.sleep(50);
                } catch (InterruptedException e) {
    
    
                }
                System.out.println(Thread.currentThread().getName() + "正在售卖" + (piao--) + "张票");
            }
        }
    }
}

O código acima tem problemas de segurança de thread

  • Condições para problemas de segurança de thread:
  1. É um ambiente multithread
  2. Existem recursos compartilhados entre vários threads
  3. Existem várias instruções operando em recursos compartilhados e as operações em recursos compartilhados não são operações atômicas

1. Sincronize blocos de código para resolver problemas de segurança de thread

  • Use o formato do bloco de código de sincronização:
    /*
    我们使用同步代码块,将可能出现线程安全问题的代码包裹起来。
    synchronized (锁对象){
        需要同步的代码
    }

		锁对象:可以是java中的任意一个对象,常new Object()。注意不可以在括号内new对象,这样每个线程持有的不是同一把锁,没有效果。需要将该对象定义为静态成员变量,被线程共享。
		需要同步的代码:可能出现线程安全的问题。(千万不可以出现死循环,这样线程会出现阻塞)
    */
public class 使用同步代码块解决线程安全问题 {
    
    
    public static void main(String[] args) {
    
    
        Myrunable1 myrunable = new Myrunable1();
        Thread th1 = new Thread(myrunable, "窗口1");
        Thread th2 = new Thread(myrunable, "窗口2");
        Thread th3 = new Thread(myrunable, "窗口3");
        th1.start();
        th2.start();
        th3.start();
    }
}
class Myrunable1 implements Runnable {
    
    
    static int piao = 100;
    //注意:多个线程要使用同一把锁
    static Object obj=new Object();
 
    @Override
    public void run() {
    
    
        while (true) {
    
    
            //同步代码块,包裹可能出现线程安全问题的代码块
            //锁对象:可以是java中的任意一个对象,常new Object()
            synchronized (obj){
    
    
                if (piao > 0) {
    
    
                    try {
    
    
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
    
    
                    }
                    System.out.println(Thread.currentThread().getName() + "正在售卖" + (piao--) + "张票");
                }
            }
            }
    }
}
/*
为什么加了同步代码块就能解决线程安全问题?
    某个线程一旦抢占cpu时间片,进入同步代码块,就会持有该锁。
    其他线程没有该锁,只能等待,无法并发执行。
    当持有锁的线程出了同步代码块,就会释放锁,然后所有线程再次争抢时间片。
    但是加锁,数据安全,效率会降低。
 */

Em segundo lugar, o método de sincronização resolve problemas de segurança de thread

  • Podemos extrair o código thread-safe em um método e adicionar synchronized ao método para transformar o método em um método sincronizado, portanto, não há necessidade de definir um objeto de bloqueio.
public class 同步方法解决线程安全问题 {
    
    
    public static void main(String[] args) {
    
    
        Myrunable2 myrunable = new Myrunable2();
        Thread th1 = new Thread(myrunable, "窗口1");
        Thread th2 = new Thread(myrunable, "窗口2");
        Thread th3 = new Thread(myrunable, "窗口3");
        th1.start();
        th2.start();
        th3.start();
    }
}

class Myrunable2 implements Runnable {
    
    
    static int piao = 100;
    @Override
    public void run() {
    
    
        //1.将可能出现线程安全问题的代码抽成方法
            maipiao();
    }

       //2.在方法上加上synchronized,将该方法变成个同步方法
    public synchronized void maipiao(){
    
    
        while (true){
    
    
            if (piao > 0) {
    
    
                try {
    
    
                    Thread.sleep(50);
                } catch (InterruptedException e) {
    
    
                }
                System.out.println(Thread.currentThread().getName() + "正在售卖" + (piao--) + "张票");
            }
        }
    }
}
/*
我们单独使用同步代码块或同步方法都可以解决线程安全问题,
但是我们混合使用同步代码块和同步方法时候,可能不能解决线程安全问题。
那么是因为同步代码块和同步方法使用的不是同一把锁。
    同步方法使用的默认锁对象是this(当将同步方法定义成静态方法时,锁对象是当前类对象的字节码对象)
    同步代码块使用的锁对象是任意java对象
解决方法:将同步代码块的锁对象与同步方法保持一致。
 */
  • Observe o objeto de bloqueio
  1. O objeto de bloqueio do bloco de código de sincronização é qualquer objeto java
  2. O objeto de bloqueio do método de sincronização é este
  3. O objeto de bloqueio do método de sincronização estático é o objeto bytecode atual
    Não misture o bloco de código de sincronização e o método de sincronização. Se você usá-lo, mantenha o objeto de bloqueio do bloco de código de sincronização consistente com o objeto de bloqueio do método de sincronização .

Três, bloqueios de bloqueio resolvem problemas de segurança de thread

  • Após o JDK5, um novo objeto de bloqueio Lock é fornecido.A implementação de Lock fornece uma gama mais ampla de operações de bloqueio do que o uso de métodos e instruções sincronizados.
  • ReentrantLock é uma classe de implementação de sua interface
  • void lock () adicionar bloqueio void unlock () liberar bloqueio
  • formato:
/*
    加锁
    lock.lock();
            try{
                可能出现线程安全的代码
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //释放锁
                lock.unlock();
            }

 */
public class jdk15之后lock锁 {
    
    
    public static void main(String[] args) {
    
    
        Myrunable3 myrunable = new Myrunable3();
        Thread th1 = new Thread(myrunable, "窗口1");
        Thread th2 = new Thread(myrunable, "窗口2");
        Thread th3 = new Thread(myrunable, "窗口3");
        th1.start();
        th2.start();
        th3.start();
    }
}

class Myrunable3 implements Runnable {
    
    
    static int piao = 100;
    //1.创建lock实现类的一个对象
    static Lock lock =new ReentrantLock();
    @Override
    public void run() {
    
    
        while (true) {
    
    
            //2.加锁
            lock.lock();
            try{
    
    
                if (piao > 0) {
    
    
                    try {
    
    
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
    
    
                    }
                    System.out.println(Thread.currentThread().getName() + "正在售卖" + (piao--) + "张票");
                }
            }catch (Exception e){
    
    
                e.printStackTrace();
            }finally {
    
    
                //3.释放锁
                lock.unlock();
            }


        }
    }
}

Acho que você gosta

Origin blog.csdn.net/m0_46988935/article/details/112864455
Recomendado
Clasificación