Java线程安全问题

    技术2025-12-12  15

    Java线程安全问题

    1 线程不安全演示

    public class Demo { public static void main(String[] args) { //线程不安全 Runnable run = new Ticket(); new Thread(run).start(); new Thread(run).start(); new Thread(run).start(); } static class Ticket implements Runnable{ //票数 private int count = 10; @Override public void run() { while (count > 0){ //卖票 System.out.println("正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println("出票成功,余票:" + count); } } } }

    显示结果:出现线程不安全问题

    正在准备卖票 正在准备卖票 正在准备卖票 出票成功,余票:9 正在准备卖票 出票成功,余票:7 正在准备卖票 出票成功,余票:8 正在准备卖票 出票成功,余票:6 正在准备卖票 出票成功,余票:5 正在准备卖票 出票成功,余票:4 正在准备卖票 出票成功,余票:3 正在准备卖票 出票成功,余票:2 正在准备卖票 出票成功,余票:2 正在准备卖票 出票成功,余票:1 正在准备卖票 出票成功,余票:0 出票成功,余票:-1 出票成功,余票:-2

    2 同步代码块

    格式:

    synchronize(锁对象){ // 线程执行的操作 }

    示例:

    public class Demo { public static void main(String[] args) { Runnable run = new Ticket(); new Thread(run, "窗口1").start(); new Thread(run, "窗口2").start(); new Thread(run, "窗口3").start(); } static class Ticket implements Runnable{ //票数 private int count = 10; private Object o = new Object(); @Override public void run() { while (true){ synchronized (o) { if (count > 0) { //卖票 System.out.println(Thread.currentThread().getName() + "正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count); }else { break; } } } } } }

    显示结果:

    窗口1正在准备卖票 窗口1出票成功,余票:9 窗口1正在准备卖票 窗口1出票成功,余票:8 窗口1正在准备卖票 窗口1出票成功,余票:7 窗口1正在准备卖票 窗口1出票成功,余票:6 窗口1正在准备卖票 窗口1出票成功,余票:5 窗口3正在准备卖票 窗口3出票成功,余票:4 窗口3正在准备卖票 窗口3出票成功,余票:3 窗口3正在准备卖票 窗口3出票成功,余票:2 窗口3正在准备卖票 窗口3出票成功,余票:1 窗口3正在准备卖票 窗口3出票成功,余票:0

    注意:

    Java中任何对象都可以当做锁对象对于不同的线程需要使用同一个锁对象

    3 同步方法

    格式:

    权限修饰符 synchronize 返回值类型 方法名(){ }

    示例:

    public class Demo7 { public static void main(String[] args) { Runnable run = new Ticket(); new Thread(run, "窗口1").start(); new Thread(run, "窗口2").start(); new Thread(run, "窗口3").start(); } static class Ticket implements Runnable{ //票数 private int count = 10; @Override public void run() { while (true){ boolean flag = sale(); if (!flag) break; } } public synchronized boolean sale(){ if (count > 0) { //卖票 System.out.println(Thread.currentThread().getName() + "正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count); return true; } return false; } } }

    显示结果:

    窗口1正在准备卖票 窗口1出票成功,余票:9 窗口1正在准备卖票 窗口1出票成功,余票:8 窗口1正在准备卖票 窗口1出票成功,余票:7 窗口1正在准备卖票 窗口1出票成功,余票:6 窗口1正在准备卖票 窗口1出票成功,余票:5 窗口1正在准备卖票 窗口1出票成功,余票:4 窗口1正在准备卖票 窗口1出票成功,余票:3 窗口1正在准备卖票 窗口1出票成功,余票:2 窗口1正在准备卖票 窗口1出票成功,余票:1 窗口1正在准备卖票 窗口1出票成功,余票:0

    注意:

    同步方法中的锁对象是this,即当前对象。如果是静态方法则是类名.class。

    4 显示锁

    格式:

    Lock l = new ReentrantLock(); l.lock(); //线程执行任务 l.unlock();

    示例:

    public class Demo { public static void main(String[] args) { Runnable run = new Ticket(); new Thread(run, "窗口1").start(); new Thread(run, "窗口2").start(); new Thread(run, "窗口3").start(); } static class Ticket implements Runnable{ //票数 private int count = 10; private Lock l = new ReentrantLock(); @Override public void run() { while (true){ l.lock(); if (count > 0) { //卖票 System.out.println(Thread.currentThread().getName() + "正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count); }else { break; } l.unlock(); } } } }

    显示结果:

    窗口1正在准备卖票 窗口1出票成功,余票:9 窗口1正在准备卖票 窗口1出票成功,余票:8 窗口1正在准备卖票 窗口1出票成功,余票:7 窗口1正在准备卖票 窗口1出票成功,余票:6 窗口1正在准备卖票 窗口1出票成功,余票:5 窗口1正在准备卖票 窗口1出票成功,余票:4 窗口1正在准备卖票 窗口1出票成功,余票:3 窗口1正在准备卖票 窗口1出票成功,余票:2 窗口1正在准备卖票 窗口1出票成功,余票:1 窗口1正在准备卖票 窗口1出票成功,余票:0

    5 公平锁与不公平锁

    公平锁:先来先得,排队抢占锁

    不公平锁:随机抢占锁

    创建锁对象是默认是不公平锁,在创建显示锁对象时,构造方法中传入true可将锁对象设置为公平锁。

    Processed: 0.012, SQL: 9