Java中解决线程安全问题的两种方式

一:同步代码块的方式解决线程的安全问题(共享数据)

< 若创建线程的方式是继承Thread类,使用同步代码块(锁)时为了确定锁的唯一性,需要将对象声明为Static类型。

< 若创建线程的方式为实现 Runnable 接口的方式,可以直接将对象放入,通过实现的方式创建多线程,本身就是共享了同一个对象。

<使用同步代码块包围操作共享数据的操作时,必须确定不能多包围也不能少包围。

  • 未加锁时的卖票程序(继承Thread类的方式创建的多线程)
public class WindowTest {
    public static void main(String[] args) {
        Window window = new Window();
        Window window1 = new Window();
        Window window2 = new Window();
        window.setName("窗口一");
        window1.setName("窗口二");
       window2.setName("窗口三");
       window.start();
       window1.start();
       window2.start();
    }
}


class Window extends Thread{
    private static int tickets=100;


    @Override
    public void run() {
       while(true){
           if (tickets>0){
               System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+tickets);//此时的静态变量是不允许声明,但是可以使用
               tickets--;
           }else{
               break;
           }
       }
    }
}

  • 会出现重票的现象
窗口二:卖票,票号为:100
窗口一:卖票,票号为:100
窗口三:卖票,票号为:100
  • 通过同步代码块解决重票问题(继承Thread类的线程)
class Window extends Thread{
    private static int tickets=100;
     static Object object=new Object();//继承Thread 类的方式实现多线程加锁需要确保锁的唯一性


    @Override
    public void run() {
       while(true){
           synchronized(object){
           if (tickets>0){
               try {
                   Thread.sleep(10);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+tickets);//此时的静态变量是不允许声明,但是可以使用
               tickets--;
           }else{
               break;
           }}
       }
    }
}
  • 通过同步代码块解决重票问题(实现Runnable接口的方式创建的线程)
public class WindowTest {
    public static void main(String[] args) {
	 Windows windows = new Windows();
        Thread thread = new Thread(windows);//多个线程共享同一个windows对象
        Thread thread1 = new Thread(windows);
        Thread thread2 = new Thread(windows);
        thread.setName("窗口1");
        thread1.setName("窗口2");
        thread2.setName("窗口3");
        thread.start();
        thread1.start();
        thread2.start();
    }
}
class Windows implements  Runnable{
private  int tickets=100;
 Object object=new Object();
    @Override
    public void run() {
        while(true){
            synchronized (object){//所有线程都用同一把锁
            if (tickets>0){
    System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+tickets);//此时的静态变量是不允许声明,但是可以使用
                tickets--;
            }else{
                break;
            }
        }}

    }
}

二:同步方法的方式解决线程安全问题

< 将操作共享数据的代码放在使用被synchronized关键字修饰的方法中

< 同样也必须确保同步方法的唯一性,当一个线程在操作共享数据时,其他的线程是绝对不允许进入的。

public class WindowTest02 {
    public static void main(String[] args) {
        Sole sole = new Sole();
        Thread thread = new Thread(sole);
        Thread thread1 = new Thread(sole);
        Thread thread2 = new Thread(sole);
        thread.setName("窗口1");
        thread1.setName("窗口2");
        thread2.setName("窗口3");
        thread.start();
        thread1.start();
        thread2.start();

    }
}

class Sole implements  Runnable{
    private static int  flags=100;
    @Override
    public void run() {
    while (true){
    show();

    }

    }
    public synchronized void show (){//始终确保操作共享数据时只有一个线程在操作,其他线程始终是等待的

        if (flags>0){
            System.out.println(Thread.currentThread().getName()+"卖票为"+flags);
            flags--;

        }
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值