【无标题】

【无标题】,第1张

【无标题】 同步安全问题:

定义卖票,当一个线程去买票时他会按照顺序进行,但是当两个线程去买票时,可能出现线程安全问题

定义一个卖票类:

其中让线程睡100毫秒,是为了使其出现线程问题,以为cpu的运行速度非常快,所以需要让拿到票的线程睡一下

public class ThreadSafe implements Runnable{
    private int ticket=100;
    @Override
    public void run() {
        while(ticket<=100&&ticket>0){
                try{
                    Thread.sleep(100);
                }
                catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("线程:"+Thread.currentThread().getName()+"取得票号为-----"+ticket--);
            }

    }
}

定义两个线程的测试类:

import com.one.ThreadSafe;

public class ThreadSafeTest {
    public static void main(String[] args) {
        ThreadSafe threadSafe=new ThreadSafe();
        Thread thread1=new Thread(threadSafe);
        Thread thread2=new Thread(threadSafe);
        thread1.start();
        thread2.start();
    }
}

结果:

线程:Thread-0取得票号为-----99
线程:Thread-1取得票号为-----100
线程:Thread-0取得票号为-----98
线程:Thread-1取得票号为-----97
线程:Thread-0取得票号为-----96
线程:Thread-1取得票号为-----96
线程:Thread-0取得票号为-----95
线程:Thread-1取得票号为-----95
线程:Thread-1取得票号为-----94
线程:Thread-0取得票号为-----94
线程:Thread-0取得票号为-----93
线程:Thread-1取得票号为-----93
线程:Thread-0取得票号为-----91
线程:Thread-1取得票号为-----92
线程:Thread-0取得票号为-----89
线程:Thread-1取得票号为-----90
线程:Thread-0取得票号为-----88
线程:Thread-1取得票号为-----87
线程:Thread-0取得票号为-----85
线程:Thread-1取得票号为-----86
线程:Thread-0取得票号为-----83
线程:Thread-1取得票号为-----84
线程:Thread-0取得票号为-----81
线程:Thread-1取得票号为-----82
线程:Thread-1取得票号为-----80
线程:Thread-0取得票号为-----79
线程:Thread-0取得票号为-----77
线程:Thread-1取得票号为-----78
线程:Thread-0取得票号为-----76
线程:Thread-1取得票号为-----75
线程:Thread-1取得票号为-----74
线程:Thread-0取得票号为-----73
线程:Thread-0取得票号为-----72
线程:Thread-1取得票号为-----72
线程:Thread-1取得票号为-----71
线程:Thread-0取得票号为-----70
线程:Thread-1取得票号为-----69
线程:Thread-0取得票号为-----68
线程:Thread-0取得票号为-----67
线程:Thread-1取得票号为-----66
线程:Thread-1取得票号为-----65
线程:Thread-0取得票号为-----64
线程:Thread-0取得票号为-----63
线程:Thread-1取得票号为-----63
线程:Thread-1取得票号为-----62
线程:Thread-0取得票号为-----61
线程:Thread-1取得票号为-----60
线程:Thread-0取得票号为-----59
线程:Thread-1取得票号为-----57
线程:Thread-0取得票号为-----58
线程:Thread-0取得票号为-----56
线程:Thread-1取得票号为-----55
线程:Thread-1取得票号为-----54
线程:Thread-0取得票号为-----53
线程:Thread-0取得票号为-----52
线程:Thread-1取得票号为-----52
线程:Thread-0取得票号为-----50
线程:Thread-1取得票号为-----51
线程:Thread-1取得票号为-----49
线程:Thread-0取得票号为-----49
线程:Thread-0取得票号为-----48
线程:Thread-1取得票号为-----47
线程:Thread-1取得票号为-----45
线程:Thread-0取得票号为-----46
线程:Thread-0取得票号为-----44
线程:Thread-1取得票号为-----44
线程:Thread-0取得票号为-----43
线程:Thread-1取得票号为-----43
线程:Thread-0取得票号为-----42
线程:Thread-1取得票号为-----42
线程:Thread-1取得票号为-----40
线程:Thread-0取得票号为-----41
线程:Thread-1取得票号为-----39
线程:Thread-0取得票号为-----38
线程:Thread-1取得票号为-----37
线程:Thread-0取得票号为-----36
线程:Thread-1取得票号为-----35
线程:Thread-0取得票号为-----34
线程:Thread-0取得票号为-----33
线程:Thread-1取得票号为-----33
线程:Thread-1取得票号为-----31
线程:Thread-0取得票号为-----32
线程:Thread-1取得票号为-----30
线程:Thread-0取得票号为-----30
线程:Thread-0取得票号为-----28
线程:Thread-1取得票号为-----29
线程:Thread-1取得票号为-----27
线程:Thread-0取得票号为-----27
线程:Thread-0取得票号为-----26
线程:Thread-1取得票号为-----25
线程:Thread-1取得票号为-----24
线程:Thread-0取得票号为-----23
线程:Thread-0取得票号为-----22
线程:Thread-1取得票号为-----21
线程:Thread-0取得票号为-----20
线程:Thread-1取得票号为-----20
线程:Thread-0取得票号为-----19
线程:Thread-1取得票号为-----19
线程:Thread-1取得票号为-----18
线程:Thread-0取得票号为-----18
线程:Thread-0取得票号为-----17
线程:Thread-1取得票号为-----16
线程:Thread-1取得票号为-----15
线程:Thread-0取得票号为-----14
线程:Thread-1取得票号为-----13
线程:Thread-0取得票号为-----12
线程:Thread-0取得票号为-----11
线程:Thread-1取得票号为-----11
线程:Thread-1取得票号为-----10
线程:Thread-0取得票号为-----10
线程:Thread-0取得票号为-----9
线程:Thread-1取得票号为-----9
线程:Thread-0取得票号为-----7
线程:Thread-1取得票号为-----8
线程:Thread-0取得票号为-----6
线程:Thread-1取得票号为-----5
线程:Thread-1取得票号为-----4
线程:Thread-0取得票号为-----4
线程:Thread-0取得票号为-----2
线程:Thread-1取得票号为-----3
线程:Thread-1取得票号为-----1
线程:Thread-0取得票号为-----1

可观察到票号 1 被两个线程同时获得了,产生了线程安全问题

解决办法: synchronized:同步代码块或者同步方法

给其业务代码上锁,当一个线程进入后则不允许另一个线程进入,要互斥访问临界资源

1、修饰代码块(同步代码块):synchronized(this) { //业务代码 }

例如:

public class ThreadSafe implements Runnable{
    private int ticket=100;
    @Override
    public void run() {
        while(ticket>0){
            synchronized(this){
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + "取得票号为-----" + ticket--);
            }
        }
    }
}

2、修饰在实例方法上(同步方法):public synchronized void run() { //业务代码 }

例如:

public class ThreadSafe implements Runnable{
    private int ticket=100;
    @Override
    public synchronized void run() {
        while(ticket>0){

                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + "取得票号为-----" + ticket--);
            }
        
    }
}

3、修饰在静态方法上(同步方法):public static synchronized void run() { //业务代码 }
例如:

public class TT {
    public static synchronized void show(){

    }
}

synchronized修饰代码块和静态方法时,是给当前class上锁,而synchronized修饰实例方法时,是给实例化对象上锁

ReentrantLock: 同步锁####

较 synchronized同步代码块和同步方法的功能,它也可以实现,功能更强大

常需要用到的两种方法:
lock()获得锁
unlock()尝试释放此锁
这两个方法要同时存在
可以借助try{} finally{}
例如:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadSafe implements Runnable{
    private static int ticket=100;
    private Lock lock=new ReentrantLock();
    public void run() {
        lock.lock();
        try{
            while(ticket>0){

                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + "取得票号为-----" + ticket--);
            }
        }
        //无论上面的代码执不执行,释放锁都要执行
        finally {
            lock.unlock();
        }

    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5703659.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存