Moosphan / Android-Daily-Interview

:pushpin:每工作日更新一道 Android 面试题,小聚成河,大聚成江,共勉之~
5.47k stars 776 forks source link

2019-03-15:如何实现多线程中的同步? #6

Open Moosphan opened 5 years ago

ADrunkenLiBai commented 5 years ago

NO 知啊

ADrunkenLiBai commented 5 years ago

多线程同步跟异步这不是两种事物吗,不是应该线程池跟线程锁吗

Alex-Cin commented 5 years ago

我了解到的, 大概是这样的几种方式:

  1. volatile-某种简单的逻辑下, 是可以的;
  2. synchronized;
  3. reentrantLock;
  4. cas=compare and swap(set), 就是 unsafe 类;
  5. handler(有点勉强, 他的实现本身依赖上面的一些技术)

@Ssuiyingsen 回答的, 和这个问题, 有点偏离, 不建议这样回答(重点在于解决同步问题, 不是怎么跑起来多个线程);

sukaidev commented 5 years ago

线程同步: 1、wait/notify 2、加锁,reentrantLock 以及读写锁 3、synchronized关键字(本质也是加锁) 4、cas

jmhjmh commented 5 years ago

多线程同步和异步不是一回事。 几种情况, 1.就是大家说的synchronized 他可以保证原子性,保证多个线程在操作同一方法时只有一个线程可以持有锁,并且操作该方法, 2.就是手动调用读写锁, 3.手动操作线程的wait和notify

  1. volatile我记得是没有原子性的,他可以保证内存可见性,在多线程的情况下保证每个线程的数据都是最新的
risechen commented 5 years ago

线程间的同步实质是保证相城中共享变量的数据同步

  1. volatile关键字,在get和set的场景下是可以的,由于get和set的时候都加了读写内存屏障,在数据可见性上保证数据同步。但是对于++这种非原子性操作,数据会出现不同步
  2. synchronized对代码块或方法加锁,结合wait,notify调度保证数据同步
  3. reentrantLock加锁结合Condition条件设置,在线程调度上保障数据同步
  4. CountDownLatch简化版的条件锁,在线程调度上保障数据同步
  5. cas=compare and swap(set), 在保证操作原子性上,确保数据同步
  6. 参照UI线程更新UI的思路,使用handler把多线程的数据更新都集中在一个线程上,避免多线程出现脏读
RedDargon commented 5 years ago

可以用 synchronized 关键词 作用在代码块上 或者静态非静态方法都可以。 或者 wait/notifyAll。 参数可以加入 volatile参数 让其做到 内存可见性。

BlockWen commented 5 years ago

多线程同步和异步不是一回事。 几种情况, 1.就是大家说的synchronized 他可以保证原子性,保证多个线程在操作同一方法时只有一个线程可以持有锁,并且操作该方法, 2.就是手动调用读写锁, 3.手动操作线程的wait和notify

  1. volatile我记得是没有原子性的,他可以保证内存可见性,在多线程的情况下保证每个线程的数据都是最新的

volitile主要是在CPU指令禁止重排和多线程访问变量时变量发生变化时,各线程的值是同时变化的。

LineCutFeng commented 5 years ago

更多的情况下,如果仅仅是一个变量的同步性,我喜欢原子类AtomicInteger AtomicBoolean等等,这样写还简单

ZHANGfeng-james commented 5 years ago

Java 理论与实践——正确使用 volatile 变量

3shenze commented 5 years ago

thread.join也算吗

xinyu618 commented 5 years ago

多线程下的线程同步,保证代码在多线程下实现 原子性 可见性 有序性 1、volatile 确保了可见性、有序性,但不能保证原子性 对于++这种操作就不能保证同步 2、synchronized 保证了可见性 有序性和原子性

micadalee commented 4 years ago

1.继承Thread类,重写run函数方法 2.实现Runnable接口,重写run函数方法 3.实现Callable接口,重写call函数方法 4.HandlerThread 5.AsyncTask很老的一种= = 6.Synchronized 同步

只有6是正确的,其他都是如何异步

gabyallen commented 4 years ago

1.继承线程类,重构运行函数方法 2.实现Runnable接口,重构运行函数方法 3.实现Callable接口,调用调用函数方法 4.HandlerThread 5.AsyncTask很老的一种= = 6.同步同步

feelschaotic commented 4 years ago
  1. 只有一个线程写,其他都是读,用 volatile
  2. 多个线程写,用 Synchronized
  3. 多个线程写+设置超时+自行决定释放,用 ReentranLock
  4. 提高效率,不单单一个线程进入临界区,用并发包,如:ConcurrentHashMap、LinkBlockingQueue、AtomicXXX。
  5. 读比写多,用 CopyOnWriteXXX
  6. 希望控制线程的并发数量,用 Semaphore 信号量
  7. 想让指定线程等待其他线程,用 CountDownLatch
ryanlijianchang commented 4 years ago

占坑

treasure-lau commented 4 years ago
  1. 同步方法
  2. 同步代码块
  3. 使用重入锁实现线程同步(ReentrantLock)
  4. 使用特殊域变量(volatile)实现同步(每次重新计算,安全但并非一致)
  5. 使用局部变量实现线程同步(ThreadLocal)以空间换时间
  6. 使用原子变量实现线程同步(AtomicInteger(乐观锁))
  7. 使用阻塞队列实现线程同步(BlockingQueue (常用)add(),offer(),put() 参考链接:https://www.cnblogs.com/cxxjohnson/p/8536257.html
Jmengfei commented 3 years ago

Java里面进行多线程通讯的主要方式就是共享内存的方式,共享内存主要关注的点有两个:可见有序原子性。Java的内存模型解决了可见性和有序性的问题,而锁解决的是原子性的问题。理想情况下我们希望做到"同步""互斥"。主要通过以下几种方式: