java复习第6天---多线程----6.3--多线程同步
目录
文章目录
内容
1、线程同步
1.1、多线程安全问题的产生
- 示例1.1-1:电影院售票问题
现在电影院正在出售流浪地球电影票,100张。
- 只有1个售票窗口(单线程):此时不会产生安全问题
- 有多个售票窗口(多线程):当每个窗口售票都不一样时,比如100张票分开,每个窗口分别销售一叠票。此时,也不会出现安全问题
- 多个售票窗口(多线程):每个售票窗口都销售者100张票,不分开。这时候,可能产生安全问题:
- 图示1.1-1:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6mdhWOB-1590502296256)(./images/sealTicket.bmp)]
1.2、多线程安全问题产生代码实现
package thread.create;
public class Ticket implements Runnable{
private int ticket = 10;
@Override
public void run() {
while(true) {
if(this.ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在售卖" + this.ticket + "号票");
ticket--;
}
}
}
}
package thread.create;
public class TestTicket1 {
public static void main(String[] args) {
Ticket t = new Ticket();
Thread t1 = new Thread(t, "一号窗口");
Thread t2 = new Thread(t, "二号窗口");
Thread t3 = new Thread(t, "三号窗口");
t1.start();
t2.start();
t3.start();
}
}
测试结果:
一号窗口正在售卖10号票
三号窗口正在售卖9号票
二号窗口正在售卖9号票
二号窗口正在售卖7号票
一号窗口正在售卖7号票
三号窗口正在售卖7号票
一号窗口正在售卖4号票
三号窗口正在售卖4号票
二号窗口正在售卖4号票
三号窗口正在售卖1号票
二号窗口正在售卖0号票
一号窗口正在售卖-1号票
1.3、多线程安全问题分析
 某一时刻在打印语句输出之前,3个线程ticket值可能相同,所有会打印相同的票,当某一个线程线程执行tickent = 0时,另外要给线程刚好执行tickent–那么可能打印-号票。归根结底,还是多线程共享同一资源,并且对共享资源进行操作引起的安全问题,怎么解决呢?
为解决多线程安全问题,java引入同步机制。同步机制有三种方式:
- 同步代码块
- 同步方法
- 锁机制
下面分别介绍使用方法。
1.4、同步代码
synchronized 关键字可以作用于方法中的某一块区域,表示只对这个区域内的资源进行互斥访问。
-
格式
synchronized(同步锁) { 需要同步的代码 } -
同步锁:对象的同步锁只是一个概念,可以想象在对象上标记了一个锁
- 所对象可以是任意类型
- 多个线程共享同一资源,需要使用相同的锁
- 在任何时刻,最多有一个线程获取同步锁,进入代码块执行,其他线程对象只能在外等着(BOLOCKED)
-
同步代码块解决多线程安全问题:
package thread.create; public class SynTicket implements Runnable{ private int ticket = 10; @Override public void run() { while(true) { synchronized(this) { if(this.ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在售卖" + this.ticket + "号票"); ticket--; } } } } } package thread.create; public class TestSynTicket1 { public static void main(String[] args) { SynTicket t = new SynTicket(); Thread t1 = new Thread(t, "一号窗口"); Thread t2 = new Thread(t, "二号窗口"); Thread t3 = new Thread(t, "三号窗口"); t1.start(); t2.start(); t3.start(); } } 测试结果: 一号窗口正在售卖10号票 一号窗口正在售卖9号票 一号窗口正在售卖8号票 二号窗口正在售卖7号票 三号窗口正在售卖6号票 二号窗口正在售卖5号票 一号窗口正在售卖4号票 二号窗口正在售卖3号票 三号窗口正在售卖2号票 三号窗口正在售卖1号票
1.5、同步方法
-
同步方法:用synchronized 修饰的方法为同步方法,能保证一个线程在访问该方法的时候,其他线程在方法外等待
-
格式
修饰符 synchronized 返回值类型 方法名(参数列表) {需要同步的代码块} -
所对象:
- 非static方法,所对象为this
- static方法,锁对象为方法所在类的字节码(.class)
-
用同步方法解决卖票完全问题:
package thread.create; public class SynMethodTicket implements Runnable{ private int ticket = 10; @Override public synchronized void run() { while(true) { if(this.ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在售卖" + this.ticket + "号票"); ticket--; } } } } package thread.create; public class TestSynMethodTicket { public static void main(String[] args) { SynMethodTicket t = new SynMethodTicket(); Thread t1 = new Thread(t, "一号窗口"); Thread t2 = new Thread(t, "二号窗口"); Thread t3 = new Thread(t, "三号窗口"); t1.start(); t2.start(); t3.start(); } } 测试结果: 一号窗口正在售卖10号票 一号窗口正在售卖9号票 一号窗口正在售卖8号票 一号窗口正在售卖7号票 一号窗口正在售卖6号票 一号窗口正在售卖5号票 一号窗口正在售卖4号票 一号窗口正在售卖3号票 一号窗口正在售卖2号票 一号窗口正在售卖1号票 -
总结:
- 锁作用代码块越少,效率相对越高
- 能用同步代码块尽量不要用同步方法
1.6、lock锁
java.util.concurrent.locks.Lock 锁提供了比同步代码块和同步方法更广泛的锁定操作,具有同步代码块和同步方法全部功能,更加体现面向对象。
Lock锁也称同步锁,加锁和释放锁方法化 了,如下
-
public void lock:加锁
-
public void unlock:释放锁
-
使用步骤:
- 成员位置创建ReentrantLock对象
- 在可能出现安全问题的代码前 使用lock.lock()方法加锁
- 在可能出现安全问题的代码后使用lock.unlock()方法释放锁
-
lock锁解决买票安全问题:
package thread.create; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TicketLock implements Runnable{ private int ticket = 10; Lock lock = new ReentrantLock(); @Override public void run() { while(true) { lock.lock(); if(this.ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在售卖" + this.ticket + "号票"); ticket--; } lock.unlock(); } } } package thread.create; public class TestTicketLock { public static void main(String[] args) { TicketLock t = new TicketLock(); Thread t1 = new Thread(t, "一号窗口"); Thread t2 = new Thread(t, "二号窗口"); Thread t3 = new Thread(t, "三号窗口"); t1.start(); t2.start(); t3.start(); } } 测试结果: 一号窗口正在售卖10号票 一号窗口正在售卖9号票 一号窗口正在售卖8号票 一号窗口正在售卖7号票 一号窗口正在售卖6号票 三号窗口正在售卖5号票 三号窗口正在售卖4号票 三号窗口正在售卖3号票 二号窗口正在售卖2号票 二号窗口正在售卖1号票
1.7、静态同步方法
静态方法的锁对象是所在类的class属性,即所在类的字节码类。
后记 :
本项目为参考某马视频开发,相关视频及配套资料可自行度娘或者联系本人。上面为自己编写的开发文档,持续更新。欢迎交流,本人QQ:806797785
前端项目源代码地址:https://gitee.com/gaogzhen/vue-leyou
后端JAVA源代码地址:https://gitee.com/gaogzhen/JAVA

3903

被折叠的 条评论
为什么被折叠?



