day22 java多线程 线程安全问题解决方案

线程安全问题

[面试题]继承Thread和实现Runnable有什么区别?

1.实现接口和继承类 - 实现接口更灵活因为可以多实现。

2.线程安全

        同步代码块 :

                继承Thread : 锁不可以是this

                实现Runnable : 锁可以是this

        同步方法

                继承Thread : 同步方法要使用静态同步方法--锁是当前类的运行时类(类信息)

                实现Runnable : 同步方法不是静态的 - 锁是this

3.共享数据(Thread要创建好几个对象,Runnable的实现类创建对象只用创建溢出)

        继承Thread : 如果共享数据是在Thread子类中声明的该共享数据需要使用static修饰

        实现Runnable : 如果共享数据是在Runnable接口的实现类中声明的共享数据不需要使用static修饰

方案一 :同步代码块

方案一 :同步代码块
    格式: synchornized(监视器/锁){
             操作共享数据的代码
         }
synchronized 关键字可以用于某个区块前面,表示只对这个区块的资源实行互斥访问。 

    说明:
        1.监视器/锁是任意类的对象。但是所有的线程用的必须是同一把锁。
        2.多个线程需要抢锁/监视器 谁抢到谁就执行同步代码块中的内容。
            其它线程需要等待 等待操作共享数据的线程执行完毕

实现Runable

public class ThreadSafeTest {
    public static void main(String[] args) {

        MyRunnable mr = new MyRunnable();
        new Thread(mr,"窗口1:").start();
        new Thread(mr,"窗口2:").start();
        new Thread(mr,"窗口3:").start();
    }
}

class MyRunnable implements Runnable{
    int ticketNumber = 100;
    Integer i = 99;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {  //三个线程用的是同一把锁
                if (ticketNumber > 0) {

                    System.out.println(Thread.currentThread().getName() + "====" + ticketNumber);
                    ticketNumber--;
                } else {
                    return;//结束方法 - 结束线程
                }
            }
        }
    }
}

继承Thread

使用继承Thread方式开启线程
注意:1.共享数据只能有一份。共享数据如果是在类中声明的那么必须用static修饰。
     2.同步监视器/锁 三个线程必须使用的是同一把。在这如果写this那么this就是三个对象就不对了。
public class ThreadSafeTest2 {
    public static void main(String[] args) {
        //创建三个线程
        new MyThread("窗口1").start();
        new MyThread("窗口2").start();
        new MyThread("窗口3").start();
    }
}

class MyThread extends Thread{
    private static int ticketNumber = 100;//如果不加static三个对象 三个属性
    public MyThread(String name){
        super(name);
    }

    @Override
    public void run() {
        while (true){
            //同步代码块
            //不可以写this因为是三个对象 --- MyThread.class当前类的运行时类的对象(类信息)
            synchronized (MyThread.class) {
                if (ticketNumber > 0) {
                    System.out.println(Thread.currentThread().getName() + "==" + ticketNumber);
                    ticketNumber--;
                } else {
                    return;
                }
            }
        }
    }
}

方案二 :同步方法

格式: [修饰符] synchronized 返回值类型 方法名([形参列表]){ 操作共享数据的代码 }

synchronized 关键字直接修饰方法,表示同一时刻只有一个线程能进入这个方法,其他线程在外面等着。

什么时候线程会死?

1.run方法结束 2.抛异常

实现Runable

同步方法的锁:
            静态方法 : 当前类的运行时类 MyThread.class

public class ThreadSafeTest {
    public static void main(String[] args) {

        MyRunnable mr = new MyRunnable();
        new Thread(mr,"窗口1:").start();
        new Thread(mr,"窗口2:").start();
        new Thread(mr,"窗口3:").start();
    }
}

class MyRunnable implements Runnable{
    int ticketNumber = 100;
    Integer i = 99;

    @Override
    public void run() {
        while (true) {
            if(!get()){//get方法的返回值为true说明有票  返回值为false说明没有票了
                return;//结束线程
            }
        }
    }
    public synchronized boolean get(){
        //操作共享数据的代码
        if (ticketNumber > 0) {
            System.out.println(Thread.currentThread().getName() + "====" + ticketNumber);
            ticketNumber--;
            return true;
        } else {
            return false;//说明票卖完了
        }
    }
}

继承Thread

同步方法的锁:
            静态方法 : 当前类的运行时类 MyThread.class
            非静态方法 : this

public class ThreadSafeTest2 {
    public static void main(String[] args) {
        //创建三个线程
        new MyThread("窗口1").start();
        new MyThread("窗口2").start();
        new MyThread("窗口3").start();
    }

}

class MyThread extends Thread{
    private static int ticketNumber = 100;//如果不加static三个对象 三个属性
    public MyThread(String name){
        super(name);
    }
    @Override
    public void run() {
        while (true){
            if (!get()){
                return;//结束线程
            }
        }
    }
    public static synchronized boolean get(){
        if (ticketNumber > 0) {
            System.out.println(Thread.currentThread().getName() + "==" + ticketNumber);
            ticketNumber--;
            return true;
        } else {
            return false;
        }
    }
}

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值