Java的同步
1、同步
同步可以防止并发访问代码块,使多个线程共享某一个资源(代码块)
2、同步的实现方式
2、1 ReentrantLock
public class MyReentrantLock {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
private ReentrantLock reentrantLock= new ReentrantLock();
private int i=0;
@Override
public void run() {
reentrantLock.lock();
try {
i++;
System.out.println("i:"+i);
}finally {
reentrantLock.unlock();
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
}
}
ReentrantLock还可以控制锁的时间,而synchronized 不行
public class MyReentrantLock {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
private ReentrantLock reentrantLock= new ReentrantLock();
private int i=0;
@Override
public void run() {
try {
if(reentrantLock.tryLock(3, TimeUnit.SECONDS)){
System.out.println(Thread.currentThread().getName() + "获取到了锁");
Thread.sleep(5000);
}else{
System.out.println(Thread.currentThread().getName() + "没有拿到锁");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//判断当前线程是否持有锁
if(reentrantLock.isHeldByCurrentThread()){
reentrantLock.unlock();
}
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
}
}
2、2 synchronized
public class Mysynchronized {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
private int i = 0;
@Override
public synchronized void run() {
i++;
System.out.println("i:"+i);
}
};
new Thread(runnable).start();
new Thread(runnable).start();
}
}
同时用锁时要注意别造成死锁的情况,死锁会造成系统堵塞
public class Data {
}
public class DeadLockRunnable implements Runnable {
public int num;
private static Data data1 = new Data();
private static Data data2 = new Data();
@Override
public void run() {
if(num == 1){
System.out.println(Thread.currentThread().getName() + "获取到了data1,等待获取data2");
//获取data1
synchronized (data1){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取data2
synchronized (data2){
System.out.println(Thread.currentThread().getName() + "用餐完毕");
}
}
}
if(num == 2){
System.out.println(Thread.currentThread().getName() + "获取到了data2,等待获取data1");
synchronized (data2){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (data1){
System.out.println(Thread.currentThread().getName() + "用餐完毕");
}
}
}
}
}
public class MyReentrantLock1 {
public static void main(String[] args) {
DeadLockRunnable runnable1 = new DeadLockRunnable();
runnable1.num = 1;
DeadLockRunnable runnable2 = new DeadLockRunnable();
runnable2.num = 2;
new Thread(runnable1,"张三").start();
new Thread(runnable2,"李四").start();
}
}
2、3 volatile
volatile修饰变量,可以让变量在多个线程同步
class MyData {
volatile int number = 0;
public void add10() {
this.number += 10;
}
}
public class VolatileVisibilityDemo {
public static void main(String[] args) {
MyData myData = new MyData();
// 启动一个线程修改myData的number,将number的值加10
new Thread(
() -> {
System.out.println("线程" + Thread.currentThread().getName()+"\t 正在执行");
try{
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
}
myData.add10();
System.out.println("线程" + Thread.currentThread().getName()+"\t 更新后,number的值为" + myData.number);
}
).start();
// 看一下主线程的值是否同步了
while (myData.number == 0) {
// 当上面的线程将number加10后,如果同步的话,那么就会跳出循环;
// 如果没有同步的话,就会一直在循环里执行
}
System.out.println("同步了!");
}
}
2、4 java.util.concurrent.atomic
如果只是对共享变量赋值,不做其他操作:
AtomicInteger、AtomicIntegerArray、AtomicLongArray等都可以解决多线程同步问题
2、5使用java.util.concurrent提供的线程安全的集合
ArrayBlockingQueue、ConcurrentHashMap等