java多线程 读取变量 synchronized 同步安全的案例
本次介绍,我使用的是synchronized 同步代码块的关键字来读取list,在写java多线程时,一定要注意
synchronized 关键字的有效范围。
ps:
如果synchronized 关键字的代码块范围太大,可能会导致 优先获取到cpu资源的第一个线程 在满足条件的情况下 一直无法跳循环,从而使得其他线程
无法给获取到被cpu调度的机会,造成:想“多线程执行代码块”的预期-》演变成了 “单线程一路走到黑 执行代码块”的惨象,也就是让多线程的预期 实际变成了单线程了。
以下 我就用1个错误的例子,和一个正确的例子给大家介绍以下吧:
1.错误的例子:实际是单线程 执行synchronized代码块的内容:
package com.cdncp.testautomation.control.schedule; public class SellTicketTest { public static void main(String[] args) { for(int i=0;i<9;i++){ TicketSell t1 = new TicketSell(); t1.setName("第"+i+"号窗口"); t1.start(); } // TicketSell t1 = new TicketSell(); // TicketSell t2 = new TicketSell(); // TicketSell t3 = new TicketSell(); // TicketSell t4 = new TicketSell(); // // t1.setName("第一号窗口"); // t2.setName("第二号窗口"); // t3.setName("第三号窗口"); // t4.setName("第四号窗口"); // // t1.start(); // t2.start(); // t3.start(); // t4.start(); } }
第二个类:
package com.cdncp.testautomation.control.schedule; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TicketSell extends Thread { private static int ticket = 20; private static final Lock lock = new ReentrantLock(); @Override public void run() { // System.out.println(this.getName() + "卖出第 " + ticket + "号票"); System.out.println(this.getName() + "卖出第 " + ticket + "号票"); while (true) { synchronized (TicketSell.class) { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // synchronized (TicketSell.class) { if (ticket > 0) { ticket--; System.out.println(this.getName() + "---------------------卖出第 " + ticket + "号票"); } // } } else { System.out.printf("%s:票已售空 \n", Thread.currentThread().getName()); break; } } } } }
执行结果:
2.正确的例子:实现多线程 执行synchronized代码块的内容:
package com.cdncp.testautomation.control.schedule; public class SellTicketTest { public static void main(String[] args) { // 方法一:创建9个线程 for(int i=0;i<9;i++){ TicketSell t1 = new TicketSell(); t1.setName("第"+i+"号窗口"); t1.start(); } // 方法二:创建9个线程 // TicketSell t1 = new TicketSell(); // TicketSell t2 = new TicketSell(); // TicketSell t3 = new TicketSell(); // TicketSell t4 = new TicketSell(); // // t1.setName("第一号窗口"); // t2.setName("第二号窗口"); // t3.setName("第三号窗口"); // t4.setName("第四号窗口"); // // t1.start(); // t2.start(); // t3.start(); // t4.start(); } }
package com.cdncp.testautomation.control.schedule; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TicketSell extends Thread { private static int ticket = 20; private static final Lock lock = new ReentrantLock(); @Override public void run() { // System.out.println(this.getName() + "卖出第 " + ticket + "号票"); System.out.println(this.getName() + "卖出第 " + ticket + "号票"); while (true) { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (TicketSell.class) { if (ticket > 0) { ticket--; System.out.println(this.getName() + "---------------------卖出第 " + ticket + "号票"); } } } else { System.out.printf("%s:票已售空 \n", Thread.currentThread().getName()); break; } } } }
执行结果: