java如何解决线程安全问题?

  1. 方式一:同步代码块
synchroized(同步监视器的对象){
需要被同步的代码
}
package threadtest;
//使用同步代码块实现Runable接口的线程
public class Ruanble {
    
    public static void main(String[] args) {
        //创建实现类的对象
        Num num=new Num();
        //将此对象作为参数传递给Thread类的构造器,创建Thread类的对象
        Thread thread1 =new Thread(num);
        Thread thread2 =new Thread(num);
        Thread thread3 =new Thread(num);
        //调用start()启动创建的Thread对象
        
        thread1.setName("线程一");
        thread2.setName("线程二");
        thread3.setName("线程三");
        
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
//创建一个类实现Runable接口
class Num implements Runnable{
    int ticket=100;
    //定义同步监视器,多个线程共同使用唯一的同步监视器
    Object obj=new Object();
    //重写run方法
    @Override
    public void run() {
    while (true) {
        synchronized (obj) {
            if (ticket>0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()  +"开始售票,票号为"+   ticket);
                ticket--;
            }else {
                break;
            }
        }
    
     }
    }
}
package threadtest;
//同步代码块实现继承Thread的线程
public class ThreadTest {

    public static void main(String[] args) {
        //创建子类对象
        EvenThread e1=new EvenThread();
        EvenThread e2=new EvenThread();
        EvenThread e3=new EvenThread();
        //调用线程的start()启动
        e1.setName("票口一");
        e2.setName("票口二");
        e3.setName("票口三");
        
        e1.start();
        e2.start();
        e3.start();
    }
    

    
}

//创建一个类继承与Thread类
class EvenThread extends Thread{
    static int ticket=100;
    //定义同步监视器,多个线程共同使用唯一的同步监视器
    static Object obj=new Object();
    //重写run方法
    @Override
    public void run() {
    while (true) {
        //synchronized (obj) {//方式一,确保同步监视器唯一
            synchronized (EvenThread.class) {//EvenThread.class是唯一的
            if (ticket>0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()  +"开始售票,票号为"+   ticket);
                ticket--;
            }else {
                break;
            }
        }
    
     }
    }
}

说明:共享数据------多个线程共同操作的数据

需要被同步的代码块,纪委操作共享的代码

同步监视器,俗称锁,任何一个类都可以充当同步监视器,但是,要求多个线程共用一个监视器

  1. 方式二:同步方法:如果操作共享数据的代码,完整的声明在相依的方法中,着我们可以考虑将此方法作为同步方法来写
  2. 非静态的同步方法的默认监视器是this,不能修改
  3. 静态的同步方法的监视器是当前类本身,不能修改
package threadtest;
//创建同步方法实现Runable的线程
public class Ruanble {
    
    public static void main(String[] args) {
        //创建实现类的对象
        Num num=new Num();
        //将此对象作为参数传递给Thread类的构造器,创建Thread类的对象
        Thread thread1 =new Thread(num);
        Thread thread2 =new Thread(num);
        Thread thread3 =new Thread(num);
        //调用start()启动创建的Thread对象
        
        thread1.setName("线程一");
        thread2.setName("线程二");
        thread3.setName("线程三");
        
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
//创建一个类实现Runable接口
class Num implements Runnable{
    int ticket=100;
    //定义同步监视器,多个线程共同使用唯一的同步监视器
    Object obj=new Object();
    //重写run方法
    @Override
    public void run() {
    while (true) {
      push();
     }
    }
    //同步方法
    public synchronized void push() {//这里有默认的同步监视器this,是唯一的
        if (ticket>0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()  +"开始售票,票号为"+   ticket);
            ticket--;
        }
    }
}

//使用同步方法的来写继承Thread类的

package threadtest;

public class ThreadTest {

    public static void main(String[] args) {
        //创建子类对象
        EvenThread e1=new EvenThread();
        EvenThread e2=new EvenThread();
        EvenThread e3=new EvenThread();
        //调用线程的start()启动
        e1.setName("票口一");
        e2.setName("票口二");
        e3.setName("票口三");
        
        e1.start();
        e2.start();
        e3.start();
    }
    

    
}

//创建一个类继承与Thread类
class EvenThread extends Thread{
    static int ticket=100;
    //定义同步监视器,多个线程共同使用唯一的同步监视器
    static Object obj=new Object();
    //重写run方法
    @Override
    public void run() {
    while (true) {
        push();
     }
    }
    //public synchronized void push() {//此时不加static,会在new EvenThred对象是,导致同步监视器不是唯一的,故加上static,让它先于类的创建而创建
        public synchronized static  void push(){
        if (ticket>0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()  +"开始售票,票号为"+   ticket);
            ticket--;
        }
    }
}

方式三使用lock锁来确保安全,见下篇博客:链接---->

https://www.cnblogs.com/ylblikestudyJava/p/12378013.html