多线程-(4.1)Synchronized

Synchronized

( /'sɪŋkrənaɪzd/):(sin k rui na z d):同步的

synchronized是Java中的关键字,可修饰实例方法,静态方法,代码块。

代码案例:

synchronized可以修饰实例方法,静态方法,代码块。
修饰实例方法:对当前实例加锁,进入同步代码前要获得当前实例的锁
修饰静态方法:对当前类对象加锁,进入同步代码前要获得当前类对象的锁
修饰代码块:指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
具体区别详见代码示例:

0.未加锁时状态

public class TestSyn implements Runnable {

    static int count = 0;

    public void increase() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }

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

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new TestSyn());
        Thread t2 = new Thread(new TestSyn());
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
    }
}

该方法启动两线程对同一个变量进行操作,期望结果为20000,但本地运行结果为:17168(每次运行结果不同,但都是小于20000),是由于两个线程同时对该变量进行操作所导致的。加锁即可解决同时进行操作的问题。

1.实例方法

public class TestSyn implements Runnable {

    static int count = 0;

    public synchronized void increase() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }

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

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new TestSyn());
        Thread t2 = new Thread(new TestSyn());
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
    }
}

此处已加锁,但本地运行结果为:15317(每次运行结果不同,但都是小于20000),说明没有锁住。分析代码,syn修饰实例方法,锁住的是对象,但是启动线程时是新new的对象,这也就意味着存在着两个不同的实例对象锁,导致两个线程都拿到了各自的锁,同时进入了increase方法,无法保证线程安全。
对demo进行改进如下(使用同一个对象启动不同线程):

public class TestSyn implements Runnable {

    static int count = 0;

    public synchronized void increase() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }

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

    public static void main(String[] args) throws InterruptedException {
        TestSyn ts = new TestSyn();
        Thread t1 = new Thread(ts);
        Thread t2 = new Thread(ts);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
    }
}

输出结果与期望一致,为20000,说明锁已生效。

2. 静态方法

public class TestSyn implements Runnable {
    public static final Object lockHelper = new Object();

    static int count = 0;

    public synchronized static void increase() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }

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

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new TestSyn());
        Thread t2 = new Thread(new TestSyn());
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
    }
}

运行结果为20000,证明锁生效。此处虽然与1的失败demo大体一样,但是成功,是因为syn修饰的是静态方法,锁的是类对象,虽然有两个不同实体,但是是同一个类对象,保证线程安全。

3. 修饰一个代码块

public class TestSyn implements Runnable {
    public static final Object lockHelper = new Object();

    static int count = 0;

    public void increase() {
        System.out.println("其他无需保证线程安全的耗时操作");
        synchronized (lockHelper) {
            for (int i = 0; i < 10000; i++) {
                count++;
            }
        }
    }

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

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new TestSyn());
        Thread t2 = new Thread(new TestSyn());
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
    }
}

运行结果为20000,证明锁生效。同2,此处锁住的是类的静态变量,所有此类的对象共用一个静态变量,所以能成功锁住,保证线程安全。
与2相比的优点在于,可以将锁粒度降低,只锁需要保证线程安全的代码,其他无需保证线程安全且耗时的操作可以同步进行,增加代码执行效率。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_2537071370

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值