使用Java进行多线程编程时可以使用synchronized关键字修饰线程
保证同时只有一个线程访问共享资源
一定程度避免出现线程资源竞争的情况
synchronized特性
当使用synchronized关键字修饰方法之后
同一时刻只有一个线程可以执行被修饰的代码块(方法)
同时,一个线程修改了共享资源的数值后,其他线程能立刻看到最新的数值
这种操作就是“加锁”,保证线程不会因竞争共享资源而出现线程安全问题
示例:
创建多个线程(该程序为5个),每个线程对计数器进行递增操作
同时使用synchronized确保线程安全
因为counter自增的操作不是一个原子操作(实际上包含了读取、增加和写入三个步骤)
所以仍然可能出现线程竞争的情况,这里使用原子类(atomic)
来避免竞态条件出现:
package Class_109_Thread_Work;
import java.util.concurrent.atomic.AtomicInteger;
public class synchronizedDemo {
private static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args){
final int THREAD_COUNT = 5;
Thread[] threads = new Thread[THREAD_COUNT];
for(int i = 0; i< THREAD_COUNT; i++){
threads[i] = new Thread(new CounterTask(), "Thread-" + i);
threads[i].start();
}
for(int i = 0; i< THREAD_COUNT; i++){
try{
threads[i].join();
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("计数器数值:"+counter.get());
}
static class CounterTask implements Runnable{
@Override
public void run(){
for(int i = 0; i< 1000; i++){
increaseCounter();
}
}
private synchronized void increaseCounter(){
counter.incrementAndGet();
}
}
}
运行:
通过在方法声明中添加synchronized关键字,将整个方法变为同步方法,确保同一时刻只有一个线程可以访问该方法
synchronized的锁机制:
- synchronized关键字是基于对象的锁来实现同步的。每个Java对象都有一个与之相关联的锁。
- 当一个线程访问某个对象的synchronized代码块或方法时,它必须先获得该对象的锁,才能执行同步代码。
- 其他线程如果想要访问该对象的synchronized代码块或方法,必须等待该线程释放锁。
- 除了对象锁外,还有类锁和静态方法锁等,它们分别用于不同的场景下保证线程安全。
示例:
package Class_109_Thread_Work;
public class SynchronizedExample {
// 示例对象
private static class ExampleObject {
// 示例对象的属性
private int value;
public ExampleObject(int value) {
this.value = value;
}
// 同步方法,使用对象锁
public synchronized void synchronizedMethod() {
System.out.println("进入同步方法,当前线程: " + Thread.currentThread().getName());
// 在同步方法中操作示例对象的属性
value++;
System.out.println("同步方法操作后的值: " + value);
}
// 静态同步方法,使用类锁
public static synchronized void staticSynchronizedMethod() {
System.out.println("进入静态同步方法,当前线程: " + Thread.currentThread().getName());
// 在静态同步方法中操作静态属性或其他静态资源
}
// 同步代码块,使用对象锁
public void synchronizedBlock() {
synchronized (this) {
System.out.println("进入同步代码块,当前线程: " + Thread.currentThread().getName());
// 在同步代码块中操作示例对象的属性
value--;
System.out.println("同步代码块操作后的值: " + value);
}
}
// 静态同步代码块,使用类锁
public static void staticSynchronizedBlock() {
synchronized (ExampleObject.class) {
System.out.println("进入静态同步代码块,当前线程: " + Thread.currentThread().getName());
// 在静态同步代码块中操作静态属性或其他静态资源
}
}
}
public static void main(String[] args) {
final ExampleObject exampleObject = new ExampleObject(0);
// 创建多个线程,并启动它们
Thread thread1 = new Thread(() -> exampleObject.synchronizedMethod());
Thread thread2 = new Thread(() -> exampleObject.synchronizedBlock());
Thread thread3 = new Thread(() -> ExampleObject.staticSynchronizedMethod());
Thread thread4 = new Thread(() -> ExampleObject.staticSynchronizedBlock());
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
运行: