Java中关于同步,异步,多线程,多线程同步,并发,并行的一些总结
来源:互联网 发布:淘宝店铺基本信息 编辑:程序博客网 时间:2024/05/07 03:29
1.同步与异步
1.1同步
在多线程的环境中,经常会碰到数据共享的情况,即当多个线程共同需要访问一个资源时,他们需要以某种顺序来确保该资源在某一时刻只能被一个线程使用,否则,程序的运行结果将是不可预料的,在这种情况下就必须对数据进行同步,例如多个线程同时对同一数据进行写操作,即当线程A需要使用某个资源时,如果这个资源正在被线程B使用,同步机制就会让线程A一直等待下去,直到线程B结束对该资源的使用后,线程A才能使用这个资源,由此可见,同步机制能够保证资源的安全。
要想实现同步操作,必须要获得每一个线程对象的锁。获得它可以保证在同一时刻只有一个线程能够进入临界区(访问互斥资源的代码块),并且在这个锁被释放前,其他线程就不能再进入这个临界区。如果还有其他线程想要获得该对象的锁,只能进入队列等待。只有当拥有该对象锁的线程退出临界区时,所才会被释放,等待队列中优先级最高的线程才能获得该锁,从而进入共享代码区。
2.多线程
实现java多线程的方法
(1)继承Thread类,重写run()方法
Thread本质上也是实现了Runnable接口的一个实例,他代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()方法。start()方法是一个本地方法,他将启动一个新线程,并执行 run()方法(只有通过start()方法调用的run()方法才能真正的起到异步的作用)。
**小提示**start()方法被调用后并不是立刻执行多线程的代码,而是使得该线程变为可运行状态,什么时候运行多线程代码是由操作系统决定的。(就绪,运行,挂起,结束)
(2)实现Runnable接口,实现run()方法。
小提示创建Thread对象,用事先Runnable接口的对象作为参数实例化改Thread对象。
实现Callable接口,重写call()方法。(这个不是重点不建议使用)
3.多线程同步
多线程同步的方法有哪些?
(1)synchronized关键字
在java中,每个对象都有一个对象锁与之相关联,该锁表明对象在任何时候只允许被一个线程所拥有,当一个线程调用对象的一段synchronized代码时,首先要获取这个锁,然后执行相应的代码,执行结束,释放锁。
synchronized关键字主要有两种用法:
1.synchronized申明方法:public synchronized void xxx();
2.synchronized代码块:synchronized(obj){}
(2)wait()方法和notify()方法
wait()方法表示放弃当前对资源的占有权并且释放对象锁进入等待状态,一直到有人通知。
notify()方法表示当前的线程已经放弃对资源的占有,通知等待的线程来获得对资源的占有权。然后运行wait()后面的语句。被唤醒的线程依旧阻塞在wait()中直到获得对象的锁
重点内容:notify()方法放弃对资源的占用但是并没有释放对象锁
notify()和wait()方法需要配合synchronized关键字使用。
**“`
public class Consumer implements Runnable {
@Override public synchronized void run() { // TODO Auto-generated method stub int count = 10; while(count > 0) { synchronized (Test. obj) { System. out.print( "B"); count --; Test. obj.notify(); // 主动释放对象资源 try { Test. obj.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
}
public class Produce implements Runnable {
@Override public void run() { // TODO Auto-generated method stub int count = 10; while(count > 0) { synchronized (Test. obj) { //System.out.print("count = " + count); System. out.print( "A"); count --; Test. obj.notify(); try { Test. obj.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
}
测试类如下:
public class Test {
public static final Object obj = new Object(); public static void main(String[] args) { new Thread( new Produce()).start(); new Thread( new Consumer()).start(); }
}
“`**
(3)Lock
a.lock():以阻塞的方式获取锁,也就是说如果获得锁,立刻返回;如果别的线程持有锁,当前线程等待,知道获取锁后返回。
b.tryLock():以非阻塞的方式获取锁。只是尝试性的去获取锁,如果取得则返回true,否则,立刻返回false。
c.tryLock(long timeout,TimeUnit unit):如果获取了锁,立刻返回true,否则会等待参数给定的时间单元,在等待的过程中,如果获取了锁,就立刻返回true,如果等待超时,返回false。
d.lockInterruptibly():如果获取了锁,立刻返回。否则当前线程处于休眠状态,直到获得锁,或者当前线程被别的线程中断。他与lock()方法最大的区别在于如果lock()方法获取不到锁,会一直处于阻塞状态,且会忽略interrupt()方法。
**`除了wait()和notify()协作完成线程同步之外,使用Lock也可以完成同样的目的。
ReentrantLock 与synchronized有相同的并发性和内存语义,还包含了中断锁等候和定时锁等候,意味着线程A如果先获得了对象obj的锁,那么线程B可以在等待指定时间内依然无法获取锁,那么就会自动放弃该锁。
但是由于synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否,而ReentrantLock使用代码实现的,系统无法自动释放锁,需要在代码中finally子句中显式释放锁lock.unlock();
同样的例子,使用lock 如何实现呢?
public class Consumer implements Runnable {
private Lock lock; public Consumer(Lock lock) { this. lock = lock; } @Override public void run() { // TODO Auto-generated method stub int count = 10; while( count > 0 ) { try { lock.lock(); count --; System. out.print( "B"); } finally { lock.unlock(); //主动释放锁 try { Thread. sleep(91L); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
}
public class Producer implements Runnable{
private Lock lock; public Producer(Lock lock) { this. lock = lock; } @Override public void run() { // TODO Auto-generated method stub int count = 10; while (count > 0) { try { lock.lock(); count --; System. out.print( "A"); } finally { lock.unlock(); try { Thread. sleep(90L); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
}
调用代码:
public class Test {
public static void main(String[] args) { Lock lock = new ReentrantLock(); Consumer consumer = new Consumer(lock); Producer producer = new Producer(lock); new Thread(consumer).start(); new Thread( producer).start(); }
}
使用建议:
在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案。`**
4.并发与并行
并发:单个处理器,轮换执行多个任务,看起来好像是多个任务同时在执行一样。
并行:多个处理器,同时执行多个任务,但是每个任务分配在一个cpu上执行。
一个形象的例子,并发就像是一个大人同时给两个婴儿喂饭,一个人喂一口。并行就是两个大人分别同时给两个婴儿喂饭。
- Java中关于同步,异步,多线程,多线程同步,并发,并行的一些总结
- 多线程相关的一些基础概念:同步、异步、并发、并行
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发、并行、同步、异步、多线程的区别
- 并发 并行 同步 异步 多线程的区别
- 并发 并行 同步 异步 多线程的区别
- spring 无状态 bean
- 按钮加载图片
- 安卓---EditText控件的使用
- 目标检测--SqueezeDet 用于自动驾驶的实时目标检测网络
- eclipse 安装完Maven插件之后启动时候弹出错误:'Updating indexes' has encountered a problem.
- Java中关于同步,异步,多线程,多线程同步,并发,并行的一些总结
- eclipse 安装完Maven插件之后启动时候弹出错误:'Updating indexes' has encountered a problem.
- [编程题] 01翻转
- Python自动化拉取Mysql数据并装载到Oracle
- 初学Docker
- 3D-warping/DIBR
- 不只是切换多语言Android(二)
- 数据库:用cmd命令导dmp数据
- MySql的一些常见笔试题(1)