Java为了解决多线程带来的安全问题,采用了同步的方式来解决安全问题。
解决多线程的安全问题,Java提供了三种方式:
同步方法
同步块
java juc包(锁机制)
线程不安全的产生,多个线程同时使用同一个资源,就会来带线程不安全问题。
例如:
public class Cinema { public static void main(String[] args) { TicketOffice office = new TicketOffice(); //创建3个售票员 Thread seller1 = new Thread(office); Thread seller2 = new Thread(office); Thread seller3 = new Thread(office); seller1.start(); seller2.start(); seller3.start(); } } class TicketOffice implements Runnable { //定义10张电影票 int ticket = 10; @Override public void run() { while (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //开始卖电影票,每售出一张电影票,就自动减去1 System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticket--) + "张票!"); } } }
结果:
出现了重复售票(一票多卖,一女多嫁)和票数为负数的情况。
加Thread.sleep()只是为了让出错的概率增大
Thread-0正在卖第10张票! Thread-1正在卖第10张票! Thread-2正在卖第10张票! Thread-1正在卖第9张票! Thread-2正在卖第9张票! Thread-0正在卖第9张票! Thread-1正在卖第8张票! Thread-2正在卖第7张票! Thread-0正在卖第8张票! Thread-0正在卖第6张票! Thread-1正在卖第4张票! Thread-2正在卖第5张票! Thread-0正在卖第3张票! Thread-2正在卖第2张票! Thread-1正在卖第3张票! Thread-1正在卖第1张票! Thread-2正在卖第-1张票! Thread-0正在卖第0张票!
同步代码块
下面是同步代码块的语法
synchronized(obj){ //需要同步的地方 //obj可以是任意共享的资源(对象),同步代码块同步的是对象 }
下面通过同步代码块来解决卖票问题
public class Cinema { public static void main(String[] args) { TicketOffice office = new TicketOffice(); //创建3个售票员 Thread seller1 = new Thread(office); Thread seller2 = new Thread(office); Thread seller3 = new Thread(office); seller1.start(); seller2.start(); seller3.start(); } } class TicketOffice implements Runnable { //定义10张电影票 int ticket = 10; Object obj = new Object();//这个一定要写在类里,不要写在方法里 //写在类里面才是共享的资源,写在方法里面,每个线程都有自己的资源,就不是共享的了 @Override public void run() { synchronized (obj) { while (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //开始卖电影票,没售出一张电影票,就自动减去1 System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticket--) + "张票!"); } } } }
同步方法
修饰符 synchronized 返回值 方法名(){ //方法体 }
通过同步方法来解决线程安全问题
public class Cinema { public static void main(String[] args) { TicketOffice office = new TicketOffice(); //创建3个售票员 Thread seller1 = new Thread(office); Thread seller2 = new Thread(office); Thread seller3 = new Thread(office); seller1.start(); seller2.start(); seller3.start(); } } class TicketOffice implements Runnable { //定义10张电影票 int ticket = 10; Object obj = new Object();//这个一定要写在类离,不要写在方法李 //写在类里面才是共享的资源,写在方法里面,每个线程都有自己的资源,就不是共享的了 @Override public void run() { sellTicket(); } //同步方法 public synchronized void sellTicket() { while (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //开始卖电影票,没售出一张电影票,就自动减去1 System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticket--) + "张票!"); } } }
参考资料:
https://www.geeksforgeeks.org/synchronized-in-java/
https://www.cnblogs.com/xckxue/p/8685675.html
阿里程序员:
https://www.jianshu.com/p/f9b1159d4fde
https://www.jianshu.com/p/2ed498b43628
https://segmentfault.com/a/1190000013512810