java多线程常用关键字与方法介绍(一)

一、synchronized

1.synchronized & 非静态方法

服务类

public class MyService{
    private int count;
    synchronized public void methodA() {
        count ++;
    }
}

线程A

public class ThreadA extends Thread {
    private MyService myService;

    public ThreadA(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.methodA();
    }
}

线程B

public class ThreadB extends Thread {
    private MyService myService;

    public ThreadB(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.methodA();
    }
}

调用类

public class Main {
    public static void main(String[] args) {
        MyService myService = new MyService();
        ThreadA threadA = new ThreadA(myService);
        ThreadB threadB = new ThreadB(myService);
        threadA.start();
        threadB.start();
    }
}

说明:

synchronized加在方法体上,表示当前只允许一个线程调用该对象的synchronized方法。即只有threadA 或threadB 一个线程进入methodA方法,另外一个线程需要等其他线程执行完后才能进入。

注意1:

public class Main {
    public static void main(String[] args) {
        MyService myServiceA = new MyService();
        MyService myServiceB = new MyService();
        ThreadA threadA = new ThreadA(myServiceA);
        ThreadB threadB = new ThreadB(myServiceB);
        threadA.start();
        threadB.start();
    }
}
如果将调用方法改为以上这样,那么threadA 和threadB 将失去同步效果,因为两个线程分别持有的是不同对象的锁。

注意2:

public class MyService{
    private int count;
    synchronized public void methodA() {
        count ++;
    }
    synchronized public void methodB() {
        count ++;
    }
    public void methodC() {
        count ++;
    }
}
同一时刻,只有一个线程进入methodA或methodB,但是进入methodC不受约束。即一个线程进入了methodA,那么另一个线程进入不了methodA也进入不了methodB,但是methodC可以随意。

2.synchronized & 静态方法

public class MyService {
    synchronized static public void methodA() {
        int count = 0;
    }
    synchronized static public void methodB() {
        int count = 0;
    }
}

说明:

synchronized static是锁定当前的类,而不再是锁定由该类创建的对象。这时以下的调用方式threadA和threadB就是同步的。
public class Main {
    public static void main(String[] args) {
        MyService myServiceA = new MyService();
        MyService myServiceB = new MyService();
        ThreadA threadA = new ThreadA(myServiceA);
        ThreadB threadB = new ThreadB(myServiceB);
        threadA.start();
        threadB.start();
    }
}

3.synchronized & 代码块

public class Block {
    private int count;
    public void methodA() {
        synchronized(this){
            count ++;
        }
    }

    private String lock = "abc";
    public void methodB() {
        synchronized(lock){
            count ++;
        }
    }
}

说明:

synchronized(this)代码块与synchronized方法是一样的效果,都是锁定当前对象。而synchronized(lock)是锁定String lock = "abc"这个对象。

注意:

如果一个线程锁定是lock = "abc",而另一个线程将lock = "abc"改为lock = "def",则两个线程锁定的是两个对象,达不到同步的效果。

二、volatile

线程类:

public class MyThread extends Thread{
    volatile private boolean isRun = true;

    public boolean isRun() {
        return isRun;
    }

    public void setRun(boolean run) {
        isRun = run;
    }

    @Override
    public void run(){
        while (isRun){
        }
    }
}

调用类

public class Main {
    public static void main(String[] args){
        try {
            MyThread myThread = new MyThread();
            myThread.start();
            Thread.sleep(10000);
            myThread.setRun(false);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }
}

说明:

如果去掉MyThread中isRun属性的volatile字段,如果程序运行在-server模式的JVM中,那么Main会陷入死循环,因为myThread.setRun(false)所设置的isRun与正在运行的线程中的isRun不是同一个。废话不多说,看图↓↓↓

线程私有堆栈数据存取示意图

线程在-server模式的JVM中运行时,首先从主内存中读取数据保存到线程私有堆栈中,然后该线程在私有堆栈中对该数值进行操作,最后再将私有堆栈中的值保存到主内存中。

因此在多线程同时访问主存中同一个值时,会造成私有堆栈与公共堆栈中的值不同步的问题,而volatile关键字就是为了解决这个问题而存在的。

当某变量声明为volatile,则线程在读取该变量时,会强制的从公共堆栈中取值。

三、wait() & notify()

线程A

public class ThreadA extends Thread {
    private Object lock;

    public ThreadA(Object lock) {
        super();
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            synchronized (lock) {
                lock.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程B

public class ThreadB extends Thread {
    private Object lock;

    public ThreadB(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        synchronized (lock) {
            lock.notify();
        }
    }
}

说明

wait()notify()都是Object类的方法,线程调用wait()notify()方法前都要获得对象级别锁,某线程调用wait()会释放锁,使当前线程停止运行,而调用notify()方法是使停止的线程重新运行。

注意

执行notify()方法后,当前线程不会立刻释放对象锁,呈wait()状态的线程也不能马上获取对象锁,要等到执行notify()方法的线程将程序执行完,当前的线程才会释放锁。
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值