1.问题的产生
原因:多个线程操作同一个共享数据。
原理:多个线程在访问共享数据时,由于CPU的随机性,一个线程还没有执行完,执行权被其他线程抢走了,这个时候就有可能出现线程安全问题。
解决方式:把操作共享数据的代码锁起来,让单一线程执行完毕才能执行其他的
2.解决方法【上锁】
三种方法的测试类【测试类相同】
public class Demo {public static void main(String[] args) {//创建线程任务对象TicketRunnable ticketRunnable = new TicketRunnable();//传递到线程对象中Thread thread1 = new Thread(ticketRunnable);Thread thread2 = new Thread(ticketRunnable);Thread thread3 = new Thread(ticketRunnable);thread1.setName("1号窗口---");thread1.start();thread2.setName("2号窗口---");thread2.start();thread3.setName("3号窗口---");thread3.start();}
}打印结果:
----------------------------------------------------------------------------------------------------
2号窗口---卖了一张票,还剩2张票
3号窗口---卖了一张票,还剩1张票
3号窗口---卖了一张票,还剩0张票
<1>同步代码块
锁对象:可以是任意对象,但是要保证唯一;
synchronized(锁对象){
多个线程访问共享数据的代码
}
//1.同步代码块
//具体实现类
public class TicketRunnable implements Runnable {int ticket = 100;//Object obj = new Object();@Overridepublic void run() {while (true) {//同步代码块//synchronized (obj)//锁对象可以是任意对象,但是必须创建且唯一//synchronized (this)//[不能直接在内部new,如果线程公用一个任务对象,则可以直接使用这个对象]synchronized (TicketRunnable.class){//类的字节码对象唯一,也可锁住if (ticket<=0){break;}else {try {Thread.sleep(100);//睡眠100毫秒模拟卖票[不能抛出]} catch (InterruptedException e) {e.printStackTrace();}ticket--;System.out.println(Thread.currentThread().getName()+"卖了一张票,还剩" + ticket + "张票");}}}}
}
<2>同步方法/静态同步方法
同步方法:一个线程执行这个方法,另一个线程就必须等待;
同步方法的锁对象:this
public class TicketRunnable implements Runnable {private static int ticket =100;@Overridepublic void run() {while (true) {//同步方法boolean flag = method();if(flag){break;}}}//同步方法 private synchronized boolean method()//同步静态方法//同步方法的锁:this//静态同步方法的锁:类名的.class字节码文件对象private static synchronized boolean method() {if (ticket<=0){return true;}else {try {Thread.sleep(100);//睡眠100毫秒模拟卖票[不能抛出]} catch (InterruptedException e) {e.printStackTrace();}ticket--;System.out.println(Thread.currentThread().getName()+"卖了一张票,还剩" + ticket + "张票");return false;}}
}
<3>lock锁手动上锁和解锁
ReentrantLock lock = new ReentrantLock(); //【具体子类或者实现类】创建锁对象
//上锁
lock.lock(); //一个线程执行到这里,其他线程就必须在这里等
//有可能产生安全问题的代码
//解锁
lock.unlock(); //等这个线程执行完了,其他线程才能进来执行。
public class TicketRunnable implements Runnable {private int ticket = 100;//创建锁对象ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {//上锁[默认打开,线程进入关闭]try {lock.lock();if (ticket <= 0) {break;} else {Thread.sleep(100);//睡眠100毫秒模拟卖票[不能抛出]ticket--;System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + ticket + "张票");}//解锁} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}}
}
3.死锁情况【面试】
产生条件:就是锁的嵌套导致
概念:当其他线程持有对方所需要的资源,导致这些线程处理等待状态,无法继续执行
public class Demo1 {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("小康同学正在走路");}}}}).start();new Thread(() -> {while (true){synchronized (objB){synchronized (objA){System.out.println("小微同学正在走路");}}}}).start();}
}打印结果:【程序不结束,且也无法向前运行】
----------------------------------------------------------------------------------------------------
小康同学正在走路
小康同学正在走路
小康同学正在走路
小康同学正在走路
小康同学正在走路
结果分析:
正常情况:小康走完objA和objB,A,B锁正常开闭;
异常情况:小康走过objA,A锁关闭,此时小薇同学走过objB,B锁关闭,次数A,B锁都关闭,导致死锁。