AndroidCoder 浅谈并发编程之线程共享
前言
前面熟悉了并发编程的一些常见的基础概念,并且较为深入地认识了线程,可以说是并发编程浅入门啦。那本篇来学习一下线程间共享和相互协作知识块
概览
线程间共享和协作
在Java中,多个线程同时访问同一对象或者访问同一个对象里同一个成员变量,这就是线程间共享的一个很常见情况。熟悉过JVM内存模型的同学,肯定对共享资源比较清楚:
- 堆:堆是在进程空间中开辟出来的,所以它是理所当然地被共享的,通过关键字new创建的是共享的
- 全局变量:是与具体某一方法无关的,是与特定线程无关;因此也是共享的
- 静态变量:是共享的
- 文件等公用资源:是共享的
非共享的资源有:栈和寄存器
线程同步(Synchronizion)
在日常开发中,线程间共享成员变量是存在一些问题的,需要
class SharedThread {
//成员变量 用于线程间共享
private int count = 0;
...
public void addCount(){
count++; // 操作count变量
}
// 一个测试线程
private static class CountThread extends Thread {
private SharedThread sharedThread;
public CountThread(SharedThread sharedThread) {
this.sharedThread = sharedThread;
}
@Override
public void run() {
for (int i = 0; i < 6666; i++) {
sharedThread.addCount();
}
}
}
public static void main(String[] args) throws InterruptedException {
SharedThread sharedThread = new SharedThread();
CountThread countThread = new CountThread(sharedThread);
CountThread countThread1 = new CountThread(sharedThread);
countThread.start();
countThread1.start();
Thread.sleep(66);
System.out.println(sharedThread.getCount());
}
}
以上示例运行结果:
7045
程序运行结束后,值是小于 13332,是由线程间共享的同步问题导致的,解决此问题需要加上 synchronized
修饰。
把以上代码稍作修改,如:
class SharedThread {
…
public synchronized void addCount() { // synchronized来修饰方法
count++;
}
…
}
修正后运行结果是没有问题的。
解决这个问题还有另一种方式
class SharedThread {
private int count = 0;
private Object object = new Object(); // 使用 Object 作为锁
…
public void addCount(){
synchronized (object) { // synchronized修饰对象
count++;
}
}
…
}
以上两种方式没有什么差别,都是对象锁。
对象锁和类锁
// 对象锁
private synchronized void lockObject1() { // 修饰成员函数
SleepTool.second(2);
System.out.println(“Object Lock1 use”);
SleepTool.second(2);
System.out.println(“Object Lock1 end”);
}
// 类锁,实际是锁类的class对象
private static synchronized void lockClass() { //修饰class对象
SleepTool.second(2);
System.out.println(“Class Lock use”);
SleepTool.second(2);
System.out.println(“Class Lock end”);
}
对象锁和对象锁之间是互不影响的,对象锁和类锁之间也是互不影响的。
线程等待(Wait)和通知(Notify)
等待、通知是属于线程间协作,一般由等待方获取锁之后进行条件检查,条件满足,则执行逻辑代码,否则不执行。
notifyAll()
方法会唤醒所有的线程,而 notify()
只会唤醒一个线程,且这个线程不一定是想唤醒的线程,因此在使用时最好使用 notifyAll()
方法。
对象锁,锁同一个对象,如果有多个线程执行方法,之间是不会有冲突,是因为调用 wait()
方法之后,会释放锁,供另外线程使用。
总结
在处理多线程共享情况时,那必须要想到对共享的方法或对象进行同步处理。可使用对象锁的方式synchronized
关键字修饰即可。
转载自:https://juejin.cn/post/7148459447013081119