- 浏览: 26379 次
- 性别:
- 来自: 上海
最新评论
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上执行。
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上执行。
发表评论
-
流式数据、批式数据、实时数据、历史数据的区别
2018-05-31 17:00 2085大数据处理系统可分为批式(batch)大数据和流式(s ... -
网络协议
2018-05-29 16:38 523一、基本概念 1、TCP连 ... -
HTTP状态码说明
2018-05-13 11:50 837HTTP状态码(HTTP Status Code)是用以表示 ... -
Spring常用注解汇总
2018-05-13 11:18 660Spring的常用注解,具体如下: 使用注解之前要开启自动 ... -
URL地址中中文乱码详解
2018-05-07 10:43 1358引言: 在Restful类的服务设计中,经常会碰到需要在URL ... -
javaScript字符串编码
2018-05-07 10:39 544javaScript中中有有三个可以对字符串编码的函数,分别是 ... -
jvm内存模型
2018-05-05 21:18 439jvm内存模型: 栈(stake):每个线程都有私有栈内存 主 ... -
常用编码总结
2018-05-05 19:59 4701.编码区别: iso8859-1: 通常叫做Latin-1, ... -
JVM设置
2018-04-18 10:00 4361、Eclise 中设置jvm内存: 修改eclipse的配置 ... -
java移动文件并编辑文件内容
2018-03-27 18:15 457package com.wonders.utils; i ... -
log4j(转:https://www.cnblogs.com/crazyacking/p/5456347.html)
2018-02-23 09:50 469log4j需要导入的包 添加配置文件 建立类文件+主函数 修改 ... -
部署多个tomcat
2017-07-20 20:56 350下面我们把配置的详细过程写在下面,以供参考:(此例以配置三 ... -
web.xml常用标签(转)
2016-11-07 22:19 488web.xml文件是用来初始化配置信息:比如welcome页面 ... -
网页顶部空几行 jsp(转)
2016-10-10 19:52 368jsp中会经常使用到使用jsp标签和jstl的标签,比如< ... -
Java的图片处理工具类(转)
2016-10-17 19:59 597//可实现以下常用功能:缩放图像、切割图像、图像类型转换、彩色 ... -
mybatis的oracle分页查询demo
2016-10-08 20:59 1070<!-- mybatis oracle分页查询 -- ... -
关于自己遇到hibernate主键策略bug
2016-10-08 20:53 327hibernate主键策略,若为sequence,主键 ... -
解压版Tomcat配置(本例Tomcat6)
2015-10-16 10:22 484一 配置Tomcat 1 下载Tomcat Zip压缩包,解压 ... -
myeclipse搭建struts项目
2015-09-28 16:54 400一、创建web project项目; 二、选 ... -
异常:Project configuration is not up-to-date with pom.xml解决方案
2015-09-24 09:13 833[size=xx-large][/size]导入maven工程 ...
相关推荐
提供的"同步异步多线程SOCKET通讯.txt"文件可能包含实际的示例代码,展示了如何在Python、Java或C++等语言中实现同步和异步多线程Socket通信。这些代码可能包括创建Server端的Socket监听,创建并管理线程池,处理...
标签“多线程”强调了Java并发编程的核心概念,如线程的创建、同步、通信和状态管理。例如,`synchronized`关键字用于确保对共享资源的互斥访问,防止数据竞争;`wait()`, `notify()`和`notifyAll()`方法用于线程间...
C#.net同步异步SOCKET通讯和多线程总结 C#.net同步异步SOCKET通讯和多线程总结是指在C#.net环境下实现的同步异步套接字通信和多线程编程的总结。套接字(Socket)是tcp/ip网络协议接口,内部定义了许多的函数和例程...
在Java中,线程并发可以通过多种方式实现,包括继承Thread类、实现Runnable接口以及使用ExecutorService和Future等高级API。下面将详细探讨这些知识点。 首先,Java中创建线程主要有两种方法。一种是通过继承Thread...
### 并发、多线程、同步异步概念解析 #### 一、并发与多线程 **并发**(Concurrency)是指多个任务看起来同时进行的一种现象。在计算机领域,特别是操作系统层面,它指的是一个时间段内有多个程序或任务都在运行...
多线程并发查询允许我们将一个大任务分解为多个小任务,每个任务在不同的线程上独立运行,从而提高查询效率。在数据库查询中,这通常适用于处理分页数据或执行并行查询。 ### 2. 线程池 Java中的线程池是通过`java....
Java多线程异步性是Java编程中一个关键的概念,特别是在设计高性能、高并发的应用时。多线程允许程序同时执行多个独立的任务,而异步性则是这些任务在不互相等待的情况下并行运行的能力,提高了系统的效率和响应速度...
本主题将深入探讨Python3中四种不同的并发模型:同步依序下载、多进程(multiprocessing)、多线程(multithreading)以及asyncio异步编程,并通过理论分析和实际案例对比它们之间的效率差异。 1. 同步依序下载: ...
本实例主要探讨如何在VC++中创建多线程,尤其是工作者线程(Worker Threads)和用户界面(UI)线程,以及如何进行线程同步和异步操作。 首先,我们要理解线程的基本概念。线程是操作系统分配CPU时间的基本单元,一...
这个“异步多线程Demo”很可能是为了帮助学习者理解并实践多线程编程而提供的一个实例。 1. **线程定义**:线程是程序执行的最小单元,每个线程都有自己的程序计数器、系统栈和局部变量。在单个进程中,可以有多个...
但同时,多线程并发也会引入一些问题,如数据竞争和同步问题。 为了解决这些问题,Java提供了多种同步机制。`synchronized`关键字用于控制对共享资源的访问,确保同一时间只有一个线程可以执行特定代码块,从而避免...
在IT行业中,尤其是在Java开发领域,异步多线程批处理是一种常见的技术手段,用于高效地处理大量数据。本文将详细解析标题为“用JAVA写的一个异步多线程批处理的组件”的核心知识点,以及如何利用这个组件来优化大...
在Java编程语言中,同步(Synchronization)与异步(Asynchronization)是两个非常重要的概念,它们对于多线程处理和并发控制有着不可替代的作用。本文将深入探讨这两个概念的区别及其在Java中的具体应用。 #### 一...
在Java中,实现多线程有多种方式,包括直接继承Thread类或者实现Runnable接口。除此之外,Java的并发工具包java.util.concurrent提供了大量方便的类和接口,如ExecutorService用于线程池管理,BlockingQueue用于线程...
本文将深入探讨如何在Winform应用中使用异步多线程和线程池。 一、线程基础 线程是操作系统分配CPU时间的基本单元,每个进程至少包含一个线程。在C#中,可以使用`System.Threading.Thread`类来创建和管理线程。通过...
在Java中,线程是轻量级的,因为它共享进程的内存空间,这使得多线程成为处理大量并发任务的有效方式。创建Java线程有两种主要方法:通过实现`Runnable`接口或继承`Thread`类。`Runnable`通常更灵活,因为它允许线程...
本篇文章将深入探讨Java中的并发同步器,并通过具体的例子来解释如何使用`FutureTask`来实现线程之间的协作。 #### 2. FutureTask简介 `FutureTask`是Java并发编程中非常重要的一个类,它是`Future`接口的一个具体...
在Java中,我们可以通过`ExecutorService`和`Future`来管理多线程任务,并获取它们的执行结果。`ExecutorService`是`java.util.concurrent`包中的一个接口,用于管理和控制线程的生命周期,如启动线程、关闭线程池等...
通过阅读这本书,开发者可以更深入地理解Java中的多线程和并发编程,掌握如何在实际项目中有效地利用这些技术。 总的来说,Java多线程和高并发编程是提升系统性能的关键技能。理解并熟练运用这些知识,能够帮助...