Java中的同步是为了保证多线程访问共享资源的安全性和正确性而引入的机制。在Java中,每个对象都有一个内部锁(也称为监视器锁或互斥锁),在使用同步时,线程必须先获得该对象的锁才能够访问共享资源,如果没有获取到锁,则线程会阻塞等待。通过使用同步块或同步方法,来对共享数据进行加锁和解锁的操作。
Java中的同步主要有以下两种方式:
- synchronized同步块
通过使用synchronized关键字,将需要同步的代码块放在一个花括号中,从而同一时刻只有一个线程能够执行指定代码块内部的代码。当一个线程进入到synchronized同步块中时,会先尝试获取对象的锁,如果获取成功,则表示线程可以执行该同步块内部的代码,否则线程会进入阻塞状态,直到对象锁被释放。
以下是一个使用synchronized同步块的示例代码:
public class MyRunnable implements Runnable {
private int count = 0;
private Object obj = new Object();
public void run() {
synchronized (obj) {
for (int i = 0; i < 5; i++) {
count++;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
}
}
public class Main {
public static void main(String[] args) {
Runnable r = new MyRunnable();
Thread t1 = new Thread(r, "Thread1");
Thread t2 = new Thread(r, "Thread2");
t1.start();
t2.start();
}
}
上述代码中,通过使用synchronized关键字,将需要同步的代码块放在了run方法内部。在两个线程同时访问count变量时,只有一个线程能够执行count++操作,其他线程会进入阻塞状态,等待获取对象锁。这样,就保证了count变量的正确性。
- synchronized同步方法
除了使用同步块外,Java还提供了一种更为简单的同步方法。在Java中,可以将需要进行同步的代码放入一个方法中,然后在方法上添加synchronized关键字,即可将该方法变成同步方法。同步方法默认会对对象进行加锁,并且同步方法的锁对象是当前实例对象。也就是说,不同实例的同步方法之间是不会有互斥现象的。
以下是一个使用synchronized同步方法的示例代码:
public class MyRunnable implements Runnable {
private int count = 0;
public synchronized void increment() {
count++;
}
public void run() {
for (int i = 0; i < 5; i++) {
increment();
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
}
public class Main {
public static void main(String[] args) {
Runnable r = new MyRunnable();
Thread t1 = new Thread(r, "Thread1");
Thread t2 = new Thread(r, "Thread2");
t1.start();
t2.start();
}
}
上述代码中,MyRunnable类中的increment方法被声明为synchronized,因此在每次调用该方法时,线程都需要先获取当前实例对象的锁,才能够执行该方法内部的代码。通过将increment方法声明为同步方法,我们可以避免线程间对count变量的竞争,保证了count的正确性。
在Java中使用同步的场景非常广泛,比如多线程操作公共资源,读写数据库等场景。通过使用同步机制,可以保证线程访问共享资源的正确性和安全性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中的同步是什么? - Python技术站