栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java语言高级-Thread类线程安全问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java语言高级-Thread类线程安全问题

hui一、线程的安全问题:

这里使用窗口售票的例子,每个窗口相当于不同的线程,当不考虑线程安全问题时,此时会出现下面的情况

窗口2 当前剩余票:3
窗口3 当前剩余票:1
窗口2 当前剩余票:0
窗口1 当前剩余票:-1

显然,-1张票是不符合现实意义的,多个线程出现安全问题的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。

也就是说如果多个线程没有共享变量(数据)时,也就不会存在安全问题!!线程并行的

如何解决:添加锁,当一个线程在操作时,其他线程不能参与进来。

使用同步机制解决安全问题方法如下。

方式一:同步代码块

1.使用接口的方式

格式:synchronized(同步监视器:obj){

//需要被同步的代码

}

说明:操作共享数据的代码,即为需要被同步的代码--->不能保护代码多了,也不能少了。

共享数据:多个线程共同操作的变量,比如本问题中的ticket。

同步监视器,俗称:锁,任何一个类的对象,都可以充当锁。

要求:多个线程必须要共用同一把锁。

补充:在实现runnable接口创建多线程的方式中,我们可以考虑this当同步监视器,在继承Thread类创建多线程的方式中,慎用this充当同步监视器,可以考虑当前类作为同步监视器。(不管用哪个,保证对象是唯一的)

下面例子是使用接口的方式解决线程安全问题

class window1 implements Runnable {
    private int ticket = 100;
    Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ' ' + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

public class windowTs {
    public static void main(String[] args) {
        window1 w1 = new window1();
        Thread t1 = new Thread(w1);
        Thread t2 = new Thread(w1);
        Thread t3 = new Thread(w1);
        t1.start();
        t2.start();
        t3.start();
    }
}
2.使用继承Thread类的方式

使用同步代码块解决继承Thread类的方式的线程安全问题

class window2 extends Thread{
    private static int ticket = 100;
    private static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            //this 是windows2类创建的对象(w1,w2,w3)此时有多个对象
            //所以此时是不安全的
//            synchronized (this) 是错误的,
            synchronized(window1.class){
                //类也是对象
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ' ' + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

public class windowTs2 {
    public static void main(String[] args) {
        window2 w2 = new window2();
        window2 w1 = new window2();
        window2 w3 = new window2();
        w1.start();
        w2.start();
        w3.start();
    }
}

注意:不能保护代码多了,也不能少了

假如synchronized把while包进去了,那么就变成了单线程了!!!下例


synchronized(window1.class){
    while (true){
                //类也是对象
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ' ' + ticket);
                    ticket--;
                } else {
                    break;
}
窗口2 当前票数:100
窗口2 当前票数:99
窗口2 当前票数:98
窗口2 当前票数:97
窗口2 当前票数:96
窗口2 当前票数:95
可以看到变成了单线程!所以不能把包含多的代码块!!! 方法二 使用同步方法解决

1.使用接口的方式

private synchronized void show(){
需要同步的代码块
}
同步方法中不用手动声明锁,用的默认的:this
class window2 implements Runnable {
    private static int ticket = 100;

    @Override
    public void run() {
        while (true) {
            show();
        }
    }

    private synchronized void show() {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ' ' + ticket);
            ticket--;
        }
    }
}


public class windowTs2 {
    public static void main(String[] args) {
        window2 w2 = new window2();
        window2 w1 = new window2();
        window2 w3 = new window2();
        Thread t1 = new Thread(w1);
        Thread t2 = new Thread(w2);
        Thread t3 = new Thread(w3);
        t1.start();
        t2.start();
        t3.start();
    }
}
2.使用继承Thread类的方式
class window1 extends Thread {
    private static int ticket = 100;
//    Object obj = new Object();

    @Override
    public void run() {
        while (true){
            show();
        }
    }
    //同步监视器是:windows1.class这个类
    private static synchronized void show() {
        if (ticket >0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ' ' + ticket);
            ticket--;
        }
    }
}
public class windowTs {
    public static void main(String[] args) {
        window1 w1 = new window1();
        window1 w2 = new window1();
        window1 w3 = new window1();
//        Thread t1 = new Thread(w1);
//        Thread t2 = new Thread(w1);
//        Thread t3 = new Thread(w1);
        w1.start();
        w2.start();
        w3.start();
    }
}

使用同步方法仍涉及到同步监视器,只是不需要我们显式的声明。

非静态的同步方法,同步监视器是:this

静态的同步方法同步监视器是:当前类本身。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/351153.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号