Java线程同步

一、问题引入

要实现三个线程,对变量count执行++操作,每个线程加完之后,输出count的值

class MyRunnable implements Runnable{

    private int count = 0;

    @Override
    public void run() {
        addCount();
    }

    private void addCount(){
        count++;
//        此处睡眠100ms,模拟可能有多个线程执行到这
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " count = " + count);
    }

}

public class ThreadTest {

    public static void main(String[] args) {
        MyRunnable r = new MyRunnable();
//        启动三个线程
        Thread t1 = new Thread(r, "t1");
        Thread t2 = new Thread(r, "t2");
        Thread t3 = new Thread(r, "t3");
        t1.start();
        t2.start();
        t3.start();
    }

}

问题结果如下:

线程t3执行完count++后,cpu轮询到t1操作count++,t1执行完count++后,cpu轮询为t2操作count++,所以就会出现三个线程打印count值时读取count值为3

要想使出现理想的效果,就要使count++和打印count后,才允许别的线程执行count++操作

注意:count也有可能最后不为3,一个线程如果count++后,没有及时写入到内存,另一个线程读到修改前的count值,从count最终的值小于3

二、对象锁

锁是任何一个类的对象,需要多个线程共用一把锁

synchronized (this),this代表MyRunnable的对象,在主方法中,创建了一个MyRunnable对象,所以可以保证只有一个MyRunnable对象,即多个线程共用一把锁

当第一个线程执行synchronized (this)时,此时线程会拿到MyRunnable对象锁,当第二个线程执行到synchronized (this)时,拿不到锁,只有当第一个线程执行完同步代码块,释放锁,第二个线程拿到锁,进入同步代码块

同步代码块:

    private void addCount(){
        synchronized (this) {
            count++;
//        此处睡眠100ms,模拟可能有多个线程执行到这
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " count = " + count);
        }
    }

同步方法:

直接在非静态方法上加上synchronized与同步代码块相同,也相当于synchronized (this)

    private synchronized void addCount() {
        count++;
//        此处睡眠100ms,模拟可能有多个线程执行到这
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " count = " + count);
    }

三、类锁

如果在主线程创建三个MyRunnable对象,用对象锁没什么作用了,因为此时有三个对象,不能保证对象唯一

同步代码块:

使用任何一个类的类锁,每个类,都有唯一一个Class对象,如MyRunnale.class,虚拟机运行期间,只有唯一一个Class对象

class MyRunnable implements Runnable {

    private static int count = 0;

    @Override
    public void run() {
        addCount();
    }

    private void addCount() {
        synchronized (MyRunnable.class) {
            count++;
//        此处睡眠100ms,模拟可能有多个线程执行到这
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " count = " + count);
        }
    }

}

public class ThreadTest {

    public static void main(String[] args) {
        MyRunnable r1 = new MyRunnable();
        MyRunnable r2 = new MyRunnable();
        MyRunnable r3 = new MyRunnable();
//        启动三个线程
        Thread t1 = new Thread(r1, "t1");
        Thread t2 = new Thread(r2, "t2");
        Thread t3 = new Thread(r3, "t3");
        t1.start();
        t2.start();
        t3.start();
    }

}

同步方法:

作用在静态方法上,相当于synchronized (MyRunnable.class)

    private static synchronized void addCount() {
        count++;
//        此处睡眠100ms,模拟可能有多个线程执行到这
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " count = " + count);
    }

四、ReentrantLock锁

synchronized锁定后,执行完同步代码块,自动的释放锁;

ReentrantLock需要手动的启动锁,手动的释放锁;

class MyRunnable implements Runnable {

    private int count = 0;

//    ReentrantLock(boolean fair) fair参数是否公平,true,先来的线程先进入同步代码块;false,线程共同竞争锁
//    1.实例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        addCount();
    }

    private void addCount() {
        try {
//            2.调用锁定方法lock()
            lock.lock();
            count++;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " count = " + count);
        } finally {
//            3.调用解锁方法unlock()
            lock.unlock();
        }
    }

}

public class ThreadTest {

    public static void main(String[] args) {
        MyRunnable r = new MyRunnable();
//        启动三个线程
        Thread t1 = new Thread(r, "t1");
        Thread t2 = new Thread(r, "t2");
        Thread t3 = new Thread(r, "t3");
        t1.start();
        t2.start();
        t3.start();
    }

}

线程同步执行的结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值