线程同步synchronized

知识点总结

  • 静态变量:在java中,静态变量指的是被static修饰的类的变量;静态变量被所有类实例对象所共享,在内存中只有一个副本,当且仅当在类初次加载时会被初始化。
  • synchronized关键字需要对同一个实例加锁才能实现同步的作用,因此在初版代码中采用先生成一个SynchronizedCounter实例,再通过MySynchronizedAddThread、MySynchronizedDelThread构造函数初始化,使两个线程共享同一个实例
  • 优化的方法:静态变量是所有实例对象共享的变量,利用静态变量的特性,可以省去初始化两个进程的步骤,代码更加简洁。
  • 使用java.util.concurrent包中的ReentrantLock可以替代synchronized加锁

一、自己写的代码

package org.meituan.javalearn.thread;

/**
 * @projectName: codebetter
 * @package: org.meituan.javalearn.thread
 * @className: SynchronizedThread
 * @author: fangjiayueyuan
 * @description: 线程同步
 * @date: 2023/5/3 上午11:13
 * @version: 1.0
 */
public class SynchronizedThread {
    public static void main(String[] args) throws InterruptedException {
        SynchronizedCounter synchronizedCounter = new SynchronizedCounter();
        Thread adder = new MySynchronizedAddThread(synchronizedCounter);
        Thread del = new MySynchronizedDelThread(synchronizedCounter);
        adder.start();
        del.start();
        adder.join();
        del.join();
        System.out.println(synchronizedCounter.count);
    }
}
class SynchronizedCounter{
    public int count=0;
    public Object locker = new Object();

}
class MySynchronizedAddThread extends Thread{
    SynchronizedCounter synchronizedCounter;
    public MySynchronizedAddThread(SynchronizedCounter synchronizedCounter){
        this.synchronizedCounter = synchronizedCounter;
    }
    @Override
    public void run() {
        synchronized (synchronizedCounter.locker){
            for (int i = 0; i < 100 ; i++) {
                synchronizedCounter.count+=1;
            }

        }
    }
}

class MySynchronizedDelThread extends Thread{
    SynchronizedCounter synchronizedCounter;
    public MySynchronizedDelThread(SynchronizedCounter synchronizedCounter){
        this.synchronizedCounter=synchronizedCounter;
    }
    @Override
    public void run() {
        synchronized (synchronizedCounter.locker){
            for (int i = 0; i < 100; i++) {
                synchronizedCounter.count-=1;
            }
        }
    }
}


二、修改后的代码

package org.meituan.javalearn.thread;

/**
 * @projectName: codebetter
 * @package: org.meituan.javalearn.thread
 * @className: SynchronizedThread
 * @author: fangjiayueyuan
 * @description: 线程同步
 * @date: 2023/5/3 上午11:13
 * @version: 1.0
 */
public class SynchronizedThread {
    public static void main(String[] args) throws InterruptedException {
        Thread adder = new MySynchronizedAddThread();
        Thread del = new MySynchronizedDelThread();
        adder.start();
        del.start();
        adder.join();
        del.join();
        System.out.println(SynchronizedCounter.count);
    }
}
class SynchronizedCounter{
    public static int count=0;
    public static Object lock = new Object();

}
class MySynchronizedAddThread extends Thread{
    @Override
    public void run() {
        synchronized (SynchronizedCounter.lock){
            for (int i = 0; i < 100 ; i++) {
                SynchronizedCounter.count+=1;
            }

        }
    }
}

class MySynchronizedDelThread extends Thread{
    @Override
    public void run() {
        synchronized (SynchronizedCounter.lock){
            for (int i = 0; i < 100; i++) {
                SynchronizedCounter.count-=1;
            }
        }
    }
}


三、构造线程安全的类

线程安全的类:可以支持多线程并发的类
下面的代码 c1在声明时需要通过final声明,通过final声明引用需要注意:
final修饰的引用一旦指向一个对象,就不能在重新指向其他对象,虽然指向不能改变,但是该引用指向的对象内部的数据是可以修改的。

package org.meituan.javalearn.thread;

/**
 * @projectName: codebetter
 * @package: org.meituan.javalearn.thread
 * @className: SafeThread
 * @author: fangjiayueyuan
 * @description: 构造线程安全的类
 * @date: 2023/5/3 下午12:28
 * @version: 1.0
 */
public class SafeThread {
    public static void main(String[] args) throws InterruptedException {
         final Counter c1=new Counter();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    c1.add(i);
                }

            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    c1.del(i);
                }

            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(c1.getCount());
    }
}
class Counter{
    private static int count=0;

    public void add(int n){
        synchronized (this){
            count+=n;
        }
    }
    public void del(int n){
        synchronized (this){
            count-=n;
        }
    }

    public int getCount() {
        return count;
    }
}


四、ReentrantLock锁

注意:下面两种方式都可以用来获取锁,且java中的锁是可重用锁,可以对一个线程反复上锁,上锁和释放锁要成对出现
方法1:

lock.lock();

方法2:

if(lock.tryLock(1, TimeUnit.SECONDS)) // 如果1秒后仍未获取到锁,tryLock()返回false,程序就可以做一些额外处理,而不是无限等待下去。

示例程序:最初的代码使用了两种方式上锁(下面代码中注释掉的部分),由于先运行的线程1,导致线程2在运行lock.lock();一直抢不到锁,JVM进程也无法退出。

package org.meituan.javalearn.thread;

import lombok.SneakyThrows;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @projectName: codebetter
 * @package: org.meituan.javalearn.thread
 * @className: ReentranceLocker
 * @author: fangjiayueyuan
 * @description: 可重入锁
 * @date: 2023/5/4 下午12:05
 * @version: 1.0
 */
public class ReentranceLocker {
    public static void main(String[] args) throws InterruptedException {
        final CounterReentranceLocker counter = new CounterReentranceLocker();
        Thread thread1 = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    counter.add(i);
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    counter.del(i);
                }
            }
        });

        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(counter.getCount());

    }
}
class CounterReentranceLocker{
    private int count;
    private final ReentrantLock lock = new ReentrantLock();

    public void add(int n) throws InterruptedException {
//        lock.lock();
        if(lock.tryLock(1, TimeUnit.SECONDS)){
            try{
                count+=n;
            }finally {
                lock.unlock();
            }
        }
//        lock.unlock();
    }
    public void del(int n) throws InterruptedException {
//        lock.lock();
        if(lock.tryLock(1, TimeUnit.SECONDS)){
            try{
                count-=n;
            }finally {
                lock.unlock();
            }
        }
//        lock.unlock();
    }

    public int getCount() {
        return count;
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值