java多线程-线程的同步

在java中要实现多线程之间的同步操作主要有如下两种方式:synchronized关键字和对象的wait()和notify()/notifyAll();

首先来看一下synchronized关键的字的使用

作用范围:

  1. 给指定对象加锁,在进入同步代码块前需要先获得指定对象的锁
package com.ziwu.learn.thread;

public class TestLock implements  Runnable{
    private Object object = new Object();
    private static int i=0;
    @Override
    public void run() {
        synchronized (object){
            increments();
        }
    }

    private void increments() {
        for(int j = 0;j < 1000000;j++){
            i++;
        }
    }

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

     因为object属于当前实例的,所以每个线程都有各自的锁,所有存在线程安全问题,结果小于2000万。

     2.作用于实例方法,相当于对当前实例加锁,在进入同步代码块前需要先获得当前实例对象的锁

    

package com.ziwu.learn.thread;

public class TestLock implements  Runnable{

    private static int i=0;
    @Override
    public void run() {
        increments();
    }

    private synchronized void increments() {
        for(int j = 0;j < 1000000;j++){
            i++;
        }
    }

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

     synchronized用于实例方法上,相当于给当前实例加锁,所以两个线程拥有不同的锁,故而不是线程安全的。

3.作用于静态方法,相当于给当前类加锁,进入同步代码前要获得当前类的锁

package com.ziwu.learn.thread;

public class TestLock implements  Runnable{

    private static int i=0;
    @Override
    public void run() {
        increments();
    }

    private static synchronized void increments() {
        for(int j = 0;j < 1000000;j++){
            i++;
        }
    }

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

这段代码的输出结果是正常的,因为静态方法是属于类的,所以相当于两个线程公用一把锁,所以是线程安全的。

看到这里如何将1.1和1.2的方法变成线程安全的那么就很容易了,核心就是让当前两个线程采用一个锁或者将方法声明为static的使用类锁。

package com.ziwu.learn.thread;

public class TestLock implements  Runnable{

    private static int i=0;
    @Override
    public void run() {
        increments();
    }

    private  synchronized void increments() {
        for(int j = 0;j < 1000000;j++){
            i++;
        }
    }

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

后面来看一个使用Object.wait(),和Object.notify()让线程协同执行,相比加锁,Object的wait和notify使得个线程可以有序调度。

这两个方法都会抛出 IllegalMonitorStateException异常,需要注意的是wait方法会释放监视器锁,大致语义是是在调用方法的时候没有获取到监视器锁就会异常,简而言之就是该方法得配合synchronized使用,

package com.ziwu.learn.thread;

public class TestWait {
    private  static  final  Object object = new Object();
    static  class T1 implements  Runnable{

        @Override
        public void run() {
            synchronized (object){
                System.out.println("t1 is start");
                try {
                    System.out.println("t1 is start wait");
                    object.wait();
                    System.out.println("t1 is end wait");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    static  class T2 implements  Runnable{

        @Override
        public void run() {
            synchronized (object){
                System.out.println("t2 is start");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2 is start notify");
                object.notify();
                try {
                    Thread.sleep(5000);
                    System.out.println("t2 is end notify");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new T1());
        Thread t2 = new Thread(new T2());
        t1.start();
        t2.start();
    }
}

该段代码的输出:

t1 is start
t1 is start wait
t2 is start
t2 is start notify
t2 is end notify
t1 is end wait‘

可以看到t2在唤醒线程t1后,t1并没有立刻执行因为t2还没有执行完成,故而监视器锁还没有释放,t1此时是拿不到锁的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值