一:线程安全
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)什么情况下会产生死锁
-
资源有限
-
同步嵌套
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(); } }