Java synchronized同步方法详解
在多线程编程中,由于线程的交叉执行可能会造成资源竞争和数据安全问题。使用Java synchronized关键字可以通过限制同时只有一个线程可以访问被synchronized修饰的代码块或方法,从而保证了线程安全性。本文将详细讲解Java synchronized同步方法的原理、用法和示例。
同步方法的原理
Java中的synchronized关键字可以修饰代码块和方法。synchronized修饰方法时,称为同步方法。当一个线程调用一个对象的同步方法时,如果没有其他线程正在访问该对象的同步方法,那么该线程将获得该对象的锁,并执行方法。当方法执行完毕后,该线程将释放该对象的锁,其他线程可以继续访问该对象的同步方法。
同步方法的用法
在方法上添加synchronized关键字
在Java中,使用synchronized关键字修饰方法时,如下所示:
public synchronized void methodName() {
// 方法体
}
使用synchronized修饰的方法可以保证线程安全,但是有以下几点需要注意:
- 每个Java对象都有一个锁,如果多个线程同时访问不同的方法,那么锁不会相互影响;
- 如果多个线程同时访问同一个对象的同步方法,那么只有一个线程能够拥有锁,其他线程需要等待锁的释放;
- 线程释放锁的方式有两种,一种是在同步方法体执行完成后自动释放锁,一种是通过return语句或抛出异常等方式手动释放锁。
操作synchronized关键字锁住的对象
使用synchronized关键字修饰的方法一般会用于锁住某个对象,下面是一个简单的示例:
public class Example {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
}
在这个示例中,每个方法都使用了synchronized关键字来保证线程安全。对于count变量,几乎所有的方法都会访问此变量,因此需要对此变量进行加锁。
示例说明
示例一:两个线程同时访问同一对象的同步方法
public class Demo {
public static void main(String[] args) throws InterruptedException {
Example example = new Example();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
example.increment();
}
}, "Thread1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
example.decrement();
}
}, "Thread2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("count=" + example.getCount());
}
}
在这个示例中,创建了两个线程分别对同一个Example对象的increment方法和decrement方法进行调用,对count变量进行加减操作。在main方法中调用了t1和t2的join方法,等待它们执行结束后输出count变量的值。
示例二:在同步方法中抛出异常
public class Demo {
public static void main(String[] args) throws InterruptedException {
Example example = new Example();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
example.increment();
}
}, "Thread1");
Thread t2 = new Thread(() -> {
try {
example.doSomething();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Thread2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("count=" + example.getCount());
}
}
public class Example {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized void doSomething() throws InterruptedException {
System.out.println("start doSomething");
Thread.sleep(1000);
throw new RuntimeException();
}
public synchronized int getCount() {
return count;
}
}
在这个示例中,t2线程调用了Example对象的doSomething方法,该方法会执行一个耗时的操作,并抛出RuntimeException异常。在t2线程中,由于未捕获该异常,导致该线程无法正常结束并释放锁,从而导致t1线程无法获得锁继续执行。因此,在使用synchronized修饰方法时,需要小心异常处理,避免死锁的发生。
总之,通过对Java synchronized关键字的详细分析和示例说明可以体会到同步方法的原理、用法和注意事项等内容,希望本文能够对Java多线程编程有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java synchronized同步方法详解 - Python技术站