一 基本概念
多个线程并发读写同一个临界资源时会发生线程并发安全问题
当多个线程同时访问同一种共享资源时,可能会造成数据的覆盖等不一致性问题,此时就需要对线程之间进行通信和协调,该机制就叫做线程的同步机制
异步操作:多线程并发的操作,各自独立运行
同步操作:多线程串行的操作,先后执行的顺序。
二 实现方式
使用synchronized关键字,就可以把有线程安全问题的代码锁起来,这样就可以达到同一时刻 仅有一个线程访问这段代码的目的。
把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。
实现方式一:
使用同步代码块的方式实现部分代码的锁定,格式如下
synchronized(类类型的引用){
编写所有需要锁定的代码
}
类类型的引用:类的对象类型的成员变量
实现方式二:
使用同步方法的方式实现所有代码的锁定。直接使用synchronized关键字来修饰整个方法即可,格式如下:
1 同步方法:
修饰符synchronized 返回值类型 方法名(方法参数){方法体;}
同步方法的锁对象是 this
2 同步静态方法:
修饰符 static synchronized 返回值类型 方法名(方法参数) {方法体;}
同步静态方法的锁对象是 类名.class
三 案例演示:
某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票
同步代码块:
public class Tickets implements Runnable{
}}
int ticket = 100; @Override public void run() { while (true) { //谁先抢到就进行加锁(锁的是这个资源对象) ->锁的就是当前的这张票 synchronized (this) { //使用同步代码块保证票的唯一性 // 判断,票数大于0就卖票,并告知是哪个窗口卖的 if (ticket > 0) { try { //让当前线程休眠,让其他线程抢到CPU执行权。 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "还剩下:" + ticket + "张票"); //卖了票之后,总票数要减1 ticket--; } else { //票卖没了,线程停止 break; } } } }
同步方法:
public class SellTicket implements Runnable { int ticket = 100; boolean flag = true; @Override public void run() { while (flag) { //调用卖票的方法(同步方法) sell(); } } public synchronized void sell() { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "还剩下:" + ticket + "张票"); ticket--; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } else { flag = false; } } }
测试类:
public class SellTicketTest {
public static void main(String[] args) {
//高并发,一个“cpu”(一个资源)
SellTicket ticket=new SellTicket();
//一个资源,三个线程线程使用,三个窗口共卖100张票
Thread t1=new Thread(ticket,"窗口1");
Thread t2=new Thread(ticket,"窗口2");
Thread t3=new Thread(ticket,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
四 同步的好处和弊端
- 好处:解决了多线程的数据安全问题
- 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率
五 线程安全类和不安全类:
当多个线程访问某个方法时,不管这些线程如何交替执行,这个类的结果行为都是我们设想的正确行为,我们就可以说这个类是线程安全类。
线程安全表示它是唯一的,例如Vector & ArrayList:
Vector的方法都是同步的,是线程安全的,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrrayList慢。ArrayList的方法不是同步的。
注意事项:
使用synchronized保证线程同步应当注意
①多个需要同步的线程在访问同步块时,看到的应该是同一个锁对象引用。
②在使用同步块时,应当减少同步范围以提高并发的执行效率。
(同步方法的加锁范围小,颗粒度更小,定位更细;同步代码块加锁范围大)
标签:同步,Thread,synchronized,线程,机制,方法,ticket From: https://www.cnblogs.com/Sco-/p/16990073.html