前言
Java是一门功能强大且广泛应用的编程语言,具有跨平台性和高效的执行速度,广受开发者喜爱。在接下来的学习过程中,我将记录学习过程中的基础语法、框架和实践技巧等,分享学习心得,对自己学习过程进行整理和总结,也希望能为其他学习Java的朋友提供一些帮助和参考。
在Java中,为了解决多线程并发导致的数据安全问题,通常使用同步机制来确保线程安全。以下是对线程同步机制的整理:
Java线程的同步机制
Java通过synchronized
关键字提供了两种同步机制来解决线程安全问题:
1. 同步代码块
synchronized(同步监视器) {
// 需要被同步的代码
}
- 同步代码:被
synchronized
包裹的代码。主要用于操作共享数据(即多个线程需要操作的数据,例如票数ticket
)。 - 同步监视器:俗称“锁”,用来控制访问共享资源。哪个线程获取了同步监视器锁,哪个线程就可以执行同步代码,其他线程必须等待。必须是唯一的。
- 注意:多个线程必须共用同一个同步监视器对象才能保证同步。
示例:
public class WindowTest {
public static void main(String[] args) {
Ticket t = new Ticket();
// 创建三个窗口(线程)
Thread window1 = new Thread(t);
Thread window2 = new Thread(t);
Thread window3 = new Thread(t);
window1.setName("窗口1");
window2.setName("窗口2");
window3.setName("窗口3");
// 启动线程
window1.start();
window2.start();
window3.start();
}
}
class Ticket implements Runnable {
private int ticketNum = 100;
@Override
public void run() {
while (true) {
synchronized (this) { // 加同步锁,确保线程安全,此时在主线程中Ticket只被实例化一次,因此this是唯一的
if (ticketNum > 0) {
// 模拟售票过程
System.out.println(Thread.currentThread().getName() + " 售出一张票,剩余票数:" + (ticketNum - 1));
ticketNum--; // 售出一张票
} else {
break; // 票卖完了,退出
}
}
// 模拟售票窗口间的时间差
try {
Thread.sleep(50); // 休眠50毫秒,模拟真实售票场景
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2. 同步方法
除了同步代码块,还可以将需要同步的代码封装在方法内,并在 方法上直接加上synchronized
修饰符,使整个方法成为同步方法。
public synchronized void sellTicket() {
// 需要被同步的代码
}
- 同步方法:无需显式指定同步监视器,默认同步监视器是当前对象(
this
),若为静态方法,则是当前类本身(类名.class
)。 - 优点:同步方法可以简化代码结构,避免手动添加
synchronized
块。
示例:
class TicketSale implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (ticket > 0) {
sellTicket();
}
}
private synchronized void sellTicket() {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + " 卖出第 " + ticket-- + " 张票");
}
}
}