多线程的线程安全

一:线程安全

1:定义

现在如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。反之则是非线程安全的。

2:线程安全以及非线程安全

都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

3:线程安全问题出现的条件

(1):首先得是是多线程环境

(2):有共享数据

(3):有多条语句操作共享数据

4:如何解决多线程安全问题呢?

基本思想:让程序处在没有安全问题的环境

怎么实现呢?

(1):把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可

(2)Java提供了同步的方式来解决

二:线程同步

1:定义

当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现

线程安全问题。要解决上述多线程并发访问一个资源的安全性问题:也就是解决重复票与不

存在票问题,Java中提供了同步机制 synchronized 来解决。

2:java 提供了三种同步机制:

1:同步代码块

synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

2:格式:
synchronized (同步锁){
//同步的代码块
}
3:例题:
public class Demo1 {
    public static void main(String[] args) {
        Ticket1 ticket1 = new Ticket1();
​
        Thread t1 = new Thread(ticket1,"一号窗口");
        Thread t2 = new Thread(ticket1,"二号窗口");
        Thread t3 = new Thread(ticket1,"三号窗口");
        Thread t4 = new Thread(ticket1,"四号窗口");
        Thread t5 = new Thread(ticket1,"五号窗口");
​
​
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}
class Ticket1 implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
​
        //这个方法写会出现卖重复票以及卖空票的现象。
        //循环条件为true保证了买票窗口永远开启
    //    while (true){
    //        //模拟买票
    //        //出一张票,让其休眠一秒
    //        if (ticket > 0){
    //            try {
    //                Thread.sleep(1000);
    //            } catch (InterruptedException e) {
    //                throw new RuntimeException(e);
    //            }
​
    //            String name = Thread.currentThread().getName();
​
    //            System.out.println(name + "正在出第【" + ticket -- + "】张票");
    //        }
    //    }
​
        //循环条件为true保证了买票窗口永远开启
        while (true){
​
            //synchronized (this)表示同步代码块
            synchronized (this){
            //模拟买票
            //出一张票,让其休眠一秒
            if (ticket > 0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
​
                String name = Thread.currentThread().getName();
​
                System.out.println(name + "正在出第【" + ticket -- + "】张票");
            }
        }
    }
    }
}

2:同步方法

(1)定义:

使用 synchronized 修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。

同步方法中的同步锁是谁呢?

对于实例方法,同步锁就是 this 。

对于 static 方法,我们使用当前方法所在类的字节码对象(类名.class)。

(2):格式
public synchronized void method(){
//可能产生安全问题的代码
}
或者
synchronized public void method(){
//可能产生安全问题的代
(3):例题
package thread0918;
​
/**
 * 同步方法
 */
public class Demo3 {
    public static void main(String[] args) {
        Ticket1 ticket1 = new Ticket1();
​
        Thread t1 = new Thread(ticket1,"一号窗口");
        Thread t2 = new Thread(ticket1,"二号窗口");
        Thread t3 = new Thread(ticket1,"三号窗口");
        Thread t4 = new Thread(ticket1,"四号窗口");
        Thread t5 = new Thread(ticket1,"五号窗口");
​
​
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}
class MyThead implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
    while (true){
        sell();
    }
    }
​
    private synchronized void sell() {
        if (ticket > 0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
​
            String name = Thread.currentThread().getName();
​
            System.out.println(name + "正在出第【" + ticket -- + "】张票");
        }
    }
​
}

3:锁机制

1:定义

java.util.concurrent.locks.Lock 机制提供了比 synchronized 代码块和 synchronized

方法更广泛的锁定操作,同步代码块/同步方法具有的功能 Lock 都有,除此之外更强大,更体

现面向对象。在 JDK 5 引入了 ReentrantLock , ReentrantLock 重入锁,是实现 Lock 接口

的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源

能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。支持公平锁和非公平锁两种

方式。

2:常用方法

public void lock() :加同步锁。

public void unlock() :释放同步锁。

3:例题
package thread0918;
​
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
​
/**
 *锁
 * public void lock() :加同步锁。
 * public void unlock() :释放同步锁。
 */
public class Demo4 {
    public static void main(String[] args) {
        Ticket1 ticket1 = new Ticket1();
​
        Thread t1 = new Thread(ticket1,"一号窗口");
        Thread t2 = new Thread(ticket1,"二号窗口");
        Thread t3 = new Thread(ticket1,"三号窗口");
        Thread t4 = new Thread(ticket1,"四号窗口");
        Thread t5 = new Thread(ticket1,"五号窗口");
​
​
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}
class MyThead1 implements Runnable{
    private int ticket = 100;
    //引入一个锁类
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            lock.lock();
            sell();
            lock.unlock();
        }
    }
​
    private void sell() {
        if (ticket > 0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
​
            String name = Thread.currentThread().getName();
​
            System.out.println(name + "正在出第【" + ticket -- + "】张票");
        }
    }
​
}
4:死锁
(1)概述

线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等

待状态,无法前往执行

(2)什么情况下会产生死锁
  1. 资源有限

  2. 同步嵌套

public class Demo {
    public static void main(String[] args) {
        Object objA = new Object();
        Object objB = new Object();
        new Thread(()->{
            while(true){
                synchronized (objA){
 //线程一
                    synchronized (objB){
                        System.out.println("线程1");
                }
            }
        }
}).start();
new Thread(()->{
    while(true){
        synchronized (objB){
//线程二
            synchronized (objA){
                System.out.println("线程2");
            }
        }
    }
}).start();
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值