总结
- 使用synchronized关键字
- 使用Lock对象
- 使用volatile关键字
- 使用原子类
- 使用线程安全的集合类
- 使用ThreadLocal类
- 使用同步工具类
使用synchronized关键字
可以用来修饰方法和代码块,使得同一时间只有一个线程可以访问被修饰的方法和代码块
public class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++;
}
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
// 创建多个线程来调用increment方法
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + example.count); // 输出结果应为2000
}
}
使用Lock对象
Java提供了Lock接口及其实现类ReentrantLock,可以使用Lock对象实现线程同步。在需要同步的代码前调用Lock对象的lock()方法获取锁,执行完后在调用unlock()释放锁
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
LockExample example = new LockExample();
// 创建多个线程来调用increment方法
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + example.count); // 输出结果应为2000
}
}
使用volatile关键字
可以使用volatile修饰变量来保证变量的可见性。当有线程改变了该变量的值时,其他线程能立即看到最新的值
public class VolatileExample {
private volatile int count = 0;
public void increment() {
count++;
}
public static void main(String[] args) {
VolatileExample example = new VolatileExample();
// 创建多个线程来调用increment方法
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + example.count); // 输出结果不一定为2000,因为volatile只能保证可见性,不能保证原子性
}
}
使用原子类
java提供了一些原子类,比如AtomicInteger、AtomicLong等,这些类提供了一些原子操作,可以保证操作的原子性,从而保证线程安全
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public static void main(String[] args) {
AtomicExample example = new AtomicExample();
// 创建多个线程来调用increment方法
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + example.count.get()); // 输出结果应为2000
}
}
使用线程安全的集合类
Java提供了一些线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList等,这些集合类在多线程环境下可以安全地进行操作
使用ThreadLocal类
ThreadLocal类可以为每个线程提供独立的变量副本,从而避免了线程安全问题
1.创建ThreadLocal对象:通过ThreadLocal的构造函数创建一个新的ThreadLocal对象。例如:
ThreadLocal<String> threadLocal = new ThreadLocal<>();
2.设置线程局部变量:通过set()方法设置当前线程的局部变量值。例如:
threadLocal.set("value");
3.获取线程局部变量:通过get()方法获取当前线程的局部变量值。例如:
String value = threadLocal.get();
4.删除线程局部变量:通过remove()方法删除当前线程的局部变量。例如:
threadLocal.remove();
使用同步工具类
Java中还提供了一些同步工具类,如CountDownLatch、CyclicBarrier、Semaphore等,可以用来控制多个线程的同步执行