java基础之线程安全问题(一)

目录

一:线程安全判断依据

二:解决线程安全问题实现(同步代码块)

1:格式

2:同步代码块的锁对象是谁?

3:同步方法的时候,锁对象又是谁呢?

4:静态同步方法,锁对象是谁?

三:卖票程序

1:分析

2:第一种实现多线程方法写卖票程序

3: 第二种实现多线程方法写卖票程序

4:注意事项


一:线程安全判断依据

1、是否存在多线程环境

2、是否存在共享数据/共享变量

3、是否有多条语句操作着共享数据/共享变量

二:解决线程安全问题实现(同步代码块)

1:格式

synchronized(锁对象){//对象要先创建可以是自定义类对象也可以是object类对象

synchronized加在方法上时在修饰符和返回值之间

需要同步的代码;

}

2:同步代码块的锁对象是谁?

任意对象

package day32;

public class SellTicketThread implements Runnable{//自定义类实现Runnable接口
    int tickets=100;//定义票总量
    boolean b =true;//一个布尔标识来控制程序的结束
    Object o = new Object();//定义一个对象
    @Override
    public void run() {
        while(b){
            synchronized (o){//同步代码块 synchronized中传入o对象
                if(tickets>0){
                    System.out.println(Thread.currentThread().getName()+"正在卖第"+tickets--+"张票");//打印窗口名字以及正在卖的票
                }
                else{
                    b=false;
                }
            }
        }
    }
}

3:同步方法的时候,锁对象又是谁呢?

this

package day32;

public class SellTicketThread implements Runnable{
    int tickets=100;
    boolean b =true;
    @Override
    public void run() {
        sellTickets();//调用方法

    }
    public void sellTickets(){
        while(b){
            synchronized (this){//传入this对象
                if(tickets>0){
                    System.out.println(Thread.currentThread().getName()+"正在卖第"+tickets--+"张票");
                }
                else{
                    b=false;
                }
            }
        }
    }
}

4:静态同步方法,锁对象是谁?

该静态同步方法所属那个类的字节码文件

字节码文件也属于一种对象。静态方法属于那个类的字节码文件即 类名.class

package day32;

public class SellTicketThread implements Runnable{
    static int tickets=100;//变量加static因为静态的方法只能调用静态的变量
    static boolean b =true;
    @Override
    public void run() {
        sellTickets();//调用方法

    }
    public static void sellTickets(){
        while(b){
            synchronized (SellTicketThread.class){//传入当前类节码文件
                if(tickets>0){
                    System.out.println(Thread.currentThread().getName()+"正在卖第"+tickets--+"张票");
                }
                else{
                    b=false;
                }
            }
        }
    }
}

三:卖票程序

1:分析

卖票程序是否满足以上线程安全条件

1、是否存在多线程环境 是,由于有三个线程模拟三个窗口

2、是否存在共享数据/共享变量 是 共享数据是100张票

3、是否有多条语句操作着共享数据/共享变量 是

2:第一种实现多线程方法写卖票程序

package day32;

public class SellTicketThread1 extends Thread {
    static int tickets =100;//定义票数
    boolean b =true;//定义标识
    Object o =new Object();
    @Override
    //重新run方法
    public void run() {
        while(b){
            synchronized (o){
                if(tickets>0){
                    System.out.println(Thread.currentThread().getName()+"正在卖第"+tickets--+"张票");
                }
                else{//如票数小于等于0,标识为false退出循环
                    b =false;
                }
            }
        }
    }
}
package day32;

public class SellTickets2 {
    public static void main(String[] args) {
        //创建自定义类对象
        SellTicketThread1 sellTicketThread = new SellTicketThread1();
        SellTicketThread1 sellTicketThread1 = new SellTicketThread1();
        SellTicketThread1 sellTicketThread2 = new SellTicketThread1();
        //他们设置名字
        sellTicketThread.setName("窗口一");
        sellTicketThread1.setName("窗口二");
        sellTicketThread2.setName("窗口三");
        //启动线程
        sellTicketThread.start();
        sellTicketThread1.start();
        sellTicketThread2.start();
    }
}

3: 第二种实现多线程方法写卖票程序

package day32;

public class SellTicketThread implements Runnable{
    int tickets=100;//定义票数
    boolean b =true;//定义标识
    Object o =new Object();
    @Override
    //重新run方法
    public void run() {
        while(b){
            synchronized (o){
                if(tickets>0){
                    System.out.println(Thread.currentThread().getName()+"正在卖第"+tickets--+"张票");
                }
                else{//如票数小于等于0,标识为false退出循环
                    b =false;
                }
            }
        }
    }
}
package day32;

public class SellTickets {
    public static void main(String[] args) {
        SellTicketThread sellTicketThread = new SellTicketThread();//创建继承Runnable类对象
        //将继承Runnable类对象传入Thread构造方法中创建三个线程
        Thread w1 = new Thread(sellTicketThread, "窗口一");
        Thread w2 = new Thread(sellTicketThread, "窗口二");
        Thread w3 = new Thread(sellTicketThread, "窗口三");
        //启动线程
        w1.start();
        w2.start();
        w3.start();

    }
}

 4:注意事项

当有共享变量用继承thread类时变量要有public satatic修饰

有共享变量时最好用继承接口方式

因为锁是多个线程公用一个是唯一的

猜你喜欢

转载自blog.csdn.net/weixin_50691399/article/details/121151803