Java小白入门——多线程之间实现同步(二)

it2024-10-28  8

Java小白入门 —— 多线程之间实现同步(二)

一. 什么是线程安全:

为什么会存在线程安全问题:

当多个线程同时共享同一全局变量或静态变量时,在做读操作时不会发送数据冲突,而在做写操作时可能会发送数据冲突问题,就会出现线程安全问题。

二. 案例:

背景: 某工厂需拖运100T货物,找了3家托运公司,用多线程模拟托运情况。

代码如下:

/** * @author MuXin * @date 2020/10/21 16:11 * * 某工厂需拖运100T货物,找了3家托运公司,用多线程模拟托运情况。 */ public class ThreadDemo { public static void main(String[] args) { ThreadGoods threadGoods = new ThreadGoods(); Thread threadA = new Thread(threadGoods, "A公司"); Thread threadB = new Thread(threadGoods, "B公司"); Thread threadC = new Thread(threadGoods, "C公司"); threadA.start(); threadB.start(); threadC.start(); } static class ThreadGoods implements Runnable { //货物总量 private int goods = 100; @Override public void run() { while (goods > 0) { try { //等待0.1s Thread.sleep(100); } catch (Exception e) { } //执行运货操作 System.out.println(Thread.currentThread().getName()+",搬运第"+(101-goods)+"T货物"); goods--; } } } }

输出结果: 当多个线程共享同一个全局成员变量时,做写的操作可能会发生数据冲突问题。

三. 线程安全解决方案:

1. 使用同步代码块

将可能出现问题的代码块包裹起来。

/** * @author MuXin * @date 2020/10/21 16:11 * <p> * 某工厂需拖运100T货物,找了3家托运公司,用多线程模拟托运情况。 */ public class ThreadDemo { public static void main(String[] args) { ThreadGoods threadGoods = new ThreadGoods(); Thread threadA = new Thread(threadGoods, "A公司"); Thread threadB = new Thread(threadGoods, "B公司"); Thread threadC = new Thread(threadGoods, "C公司"); threadA.start(); threadB.start(); threadC.start(); } static class ThreadGoods implements Runnable { //自定义多线程同步锁 private Object mutex = new Object(); //货物总量 private int goods = 100; @Override public void run() { while (goods > 0) { try { //等待0.1s Thread.sleep(100); } catch (Exception e) { } synchronized (mutex) { if(goods > 0) { try { //等待0.1s Thread.sleep(100); } catch (Exception e) { } //执行运货操作 System.out.println(Thread.currentThread().getName() + ",搬运第" + (101 - goods) + "T货物"); goods--; } } } } } }

运行结果:

2. 使用同步函数(synchronized锁)

在方法上修饰synchronized称为同步函数; synchronized使用的锁是this锁。

/** * @author MuXin * @date 2020/10/21 16:11 * <p> * 某工厂需拖运100T货物,找了3家托运公司,用多线程模拟托运情况。 */ public class ThreadGoods implements Runnable { //货物总量 private int goods = 100; //自定义多线程同步锁 private Object mutex = new Object(); @Override public void run() { while (goods > 0) { try { //等待0.1s Thread.sleep(100); } catch (Exception e) { } moveGoods(); } } public synchronized void moveGoods() { if (goods > 0) { try { //等待0.1s Thread.sleep(100); } catch (Exception e) { } //执行运货操作 System.out.println(Thread.currentThread().getName() + ",搬运第" + (101 - goods) + "T货物"); goods--; } } }

执行结果:

3. 静态同步函数

在方法上加static关键字,使用synchronized关键词修饰,或者使用类.class文件; 静态同步函数使用的锁是该函数所属字节码文件对象。

/** * @author MuXin * @date 2020/10/21 16:11 * <p> * 某工厂需拖运100T货物,找了3家托运公司,用多线程模拟托运情况。 */ public class ThreadGoods implements Runnable { //货物总量 private int goods = 100; //自定义多线程同步锁 private Object mutex = new Object(); @Override public void run() { while (goods > 0) { try { //等待0.1s Thread.sleep(100); } catch (Exception e) { } moveGoods(); } } public void moveGoods() { synchronized (ThreadGoods.class) { if (goods > 0) { try { //等待0.1s Thread.sleep(100); } catch (Exception e) { } //执行运货操作 System.out.println(Thread.currentThread().getName() + ",搬运第" + (101 - goods) + "T货物"); goods--; } } } }

执行结果:

四. 多线程死锁:

1. 什么是多线程死锁:

在同步中嵌套同步,俗称套娃,导致锁无法释放。

2. 如何避免死锁:

1. 加锁顺序(线程按照一定的顺序加锁) 2. 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁) 3. 死锁检测

五. 常见面试题:

1. 什么是线程安全

当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。

2. 如何解决多线程之间的线程安全问题?

1. 使用同步代码块; 2. 使用 synchronized 锁; 3. 使用静态同步函数。

3. 为什么使用线程同步或使用锁之后能解决线程安全问题?

当会发生数据冲突问题时,使得同一时间只能执行一个线程,其他线程处于阻塞状态,在执行完之后释放锁,交给下一个线程执行。

4. 什么是多线程之间的同步?

在多线程情况下,当多个线程共享统一资源时,不会受到其他线程的影响。

5. 什么是同步代码块?

就是将可能出现线程安全的代码包裹起来,使得同一时间只能有一个线程执行被包裹的代码,其他线程处于阻塞状态。

6. 同步代码块和同步函数的区别?

同步代码块是自定义锁(明锁) 同步函数是使用的 this 锁

7. 同步函数和静态同步函数的区别?/ 例如现在一个静态方法和一个非静态静态怎么实现同步?

同步函数使用的 this 锁; 静态同步函数使用的是字节码文件,即类.class

8. 什么是死锁?

同步中嵌套同步,俗称套娃。
最新回复(0)