06_Java多线程、线程间通信
1. 线程的概念
1.1多进程与多线程
进程:一个正在执行的程序.每个进程执行都有一个执行顺序,该顺序是一个执行路径,或叫一个控制单元. 一个进程至少有一个线程.
线程:就是进程中的一个独立的控制单元. 线程控制这进程的执行.
多进程的缺点:进程切换开销大;进程间的通信很不方便。
多线程: 指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务,线程切换的开销小 。
1.2线程的状态
Java语言使用Thread类及其子类的对象来表示线程,新建的线程在它的一个完整的生命周期通常要经历5种状态.
冻结状态:在sleep和wait时, 既没有运行资格,有没有执行权
阻塞状态: 具备运行资格, 没有执行权
1.3线程调度与优先级(多线程的特性:随机性)
Java采用抢占式调度策略,下面几种情况下,当前线程会放弃CPU:
(1)当前时间片用完;
(2)线程在执行时调用了yield() 或sleep() 方法主动放弃;
(3)进行I/O 访问,等待用户输入,导致线程阻塞;或者为等候一个条件变量,线程调用wait()方法;
(4)有高优先级的线程参与调度。
线程的优先级用数字来表示,范围从1~10。主线程的默认优先级为5
Thread.MIN_PRIORITY=1
Thread.NORM_PRIORITY=5
Thread.MAX_PRIORITY=10
2. 多线程编程方法
2.1 Thread类简介
Thread类综合了Java程序中一个线程需要拥有的属性和方法,其构造方法如下:
public Thread (ThreadGroup group,Runnable target,String name);
public Thread();
public Thread(Runnable target);
public Thread(Runnable target,String name);
public Thread(String name);
public Thread(ThreadGroup group,Runnable target);
public Thread(ThreadGroup group,String name);
Thread类的主要方法以及功能如表
2.2 继承Thread类实现多线程
需要重写run方法实现线程的任务.需要注意的是,程序中不要直接调用此方法,而是调用线程对象的start()方法启动线程,让其进入可调度状态,线程获得调度自动执行run()方法.
2.3 实现Runnable接口编写多线程
通过 Thread 类的构造函数public Thread(Runnable target)可以将一个Runnable 接口对象传递给线程,线程在调度时将自动调用Runnable 接口对象的run方法。
实现方式和继承方法的区别:
实现方式的好处:避免了单继承的局限性.在定义线程时,建议使用实现方式.
3. 线程资源的同步处理
3.1 临界资源问题
Java对于多线程的安全问题提供了专业的解决方式: 就是同步代码块
synchronized(对象) {
需要被同步的代码
}
对象如同锁,持有锁的线程可以在同步中执行.
没有持有锁的线程及时获取cpu的执行权,也进不去,因为没有获取锁.
同步的前提:
1.必须要有两个或者以上的线程
2.必须要多个线程使用同一个锁
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源.
同步函数使用的是哪个锁:
函数需要被对象调用,那么函数都有一个所属对象的引用.就是this.
所以同步函数使用的锁是this锁.静态函数使用的是该方法所在类的字节码文件对象.
懒汉式增强
class Single{
private Single(){}
private static Single s = null;
public static Single getInstance(){
if(s == null){
synchronized(Single.class){
if(s == null)
s = new Single();
}
}
return s;
}
}
3.2 wait()和notify()
3.3 避免死锁
多个线程相互等待对方释放持有的锁,并且在得到对方锁之前不释放自己的锁.(自己能写一个死锁代码)
/*
* 死锁: 同步中嵌套同步容易发生
*/ public class LockDemo { public static void main(String[] args) {
Test t = new Test(false);
Test t2 = new Test(true);
new Thread(t).start();
new Thread(t2).start(); } } class Test implements Runnable{
private boolean flag;
Test(boolean flag){
this.flag = flag;
}
public void run(){
if(flag){
try{Thread.sleep(30);}catch(Exception e){}
synchronized(KK.oa){
System.out.println("if a");
synchronized(KK.ob){
System.out.println("if b");
}
}
}
else{
synchronized(KK.ob){
System.out.println("else b");
synchronized(KK.oa){
System.out.println("else a");
}
}
}
}
} //自定义两个锁
class KK{
static Object oa = new Object();
static Object ob = new Object();
}
4. 线程间通信
思考1: wait(),notify(),nofifyAll()用来操作线程为什么定义在Object类中?
1.这些方法存在同步中,用来操作同步中的线程,必须要标志它们所操作线程的只有锁.
2.使用这些方法必须标识出所属同步的锁,只有同一个锁上被等待线程,可以被同一个锁上notify唤醒.不可以对不同锁中的线程进行唤醒.
3.锁可以是任意对象,所以任意对象调用的方法一定定义Object类中.
思考2:wait(),sleep()有什么区别?
wait():释放资源,释放锁
sleep():释放资源,不释放锁
//线程通信: 取mike, 取丽丽
public class Demo2 { public static void main(String[] args) {
Person p = new Person();
new Thread(new Input(p)).start();
new Thread(new Output(p)).start();
} } class Person{
private String name ;
private String sex ;
private boolean flag = false; public synchronized void set(String name, String sex){
//flag为true,表示已存在
if(flag){
try {wait();}catch (InterruptedException e) {e.printStackTrace();}
}
//flag为false,表示没人可加
this.name = name;
this.sex = sex;
flag = true;
this.notify();
} public synchronized void out(){
//flag为false,表示无人没法取
if(!flag){
try {wait();}catch (InterruptedException e) {e.printStackTrace();}
}
//flag为true,表示有人可以取出
System.out.println(toString());
flag = false;
this.notify();
} public String toString(){
return "姓名:"+name+"性别:"+sex;
}
} class Input implements Runnable{
private Person p; Input(Person p){
this.p = p;
} public void run(){
boolean flag = false;
while(true){
if(flag){
p.set("likai","男");
flag = false;
}
else{
p.set("tangll","女");
flag = true;
}
}
}
} class Output implements Runnable{
private Person p; Output(Person p){
this.p = p;
} public void run(){
while(true){
p.out();
}
}
}
线程通信Demo1
public class Demo3 { public static void main(String[] args) {
Bridge b = new Bridge();
for(int i=1;i<6;i++){
new Thread(new Person(b,"由北向南第"+i+"人")).start();
} for(int i=1;i<7;i++){
new Thread(new Person(b,"由南向北第"+i+"人")).start();
}
}
} class Bridge{
private String name;
private boolean flag;
public synchronized void UpBridge(){
if(flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = true; }
public synchronized void DownBridge(){
flag = false;
notifyAll();
}
} class Person implements Runnable{
private Bridge bridge;
private String pName; Person(Bridge bridge, String pName){
this.bridge = bridge;
this.pName = pName;
} public void run() {
bridge.UpBridge();
try{
Thread.sleep(80);
}catch(InterruptedException e){}
bridge.DownBridge();
System.out.println(pName);
} }
过桥问题
生产消费者问题
生产消费者问题--JDK1.5提供的多线程升级解决方法
将同步synchronized替换成Lock操作.
将Object中的wait,notify,notifyAll方法替换成Condition对象.
该对象可以Lock锁进行获取.
该实例中,实现了本方只唤醒对方的操作.
停止线程
1.定义循环结束标记
因为线程运行代码一般都是循环,只是控制了循环即可.
2.使用interrupt(中断)方法: 该方法是强制结束线程的冻结状态,使线程回到运行状态中来.这样就可以操作标记结束.
(注)stop方法和suspend方法已过时不在再使用.
setDeamon()方法
标记为后台线程, 当所有前台前程结束后会Java虚拟机退出. 该方法必须在启动线程前调用.
join()方法
等待该线程终止, 其实是抢夺CPU执行权.
当A线程执行到B线程的.join()方法, A就会等待. 等B线程都执行完, A才会执行. join可以用来临时加入线程执行.
toString()
返回该线程的字符串表示形式,包括线程名称,优先级和线程组
yield()
暂停当前执行的线程对象,并执行其他线程
06_Java多线程、线程间通信的更多相关文章
- Java多线程——线程间通信
Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线 ...
- 多线程-线程间通信-多生产者多消费者问题(JDK1.5后Lock,Condition解决办法及开发中代码范例)
1 package multithread4; 2 3 import java.util.concurrent.locks.Condition; 4 import java.util.concurre ...
- 多线程-线程间通信-多生产者多消费者问题解决(notifyAll)
1 package multithread4; 2 3 /* 4 * 生产者,消费者. 5 * 6 * 多生产者,多消费者的问题. 7 * 8 * if判断标记,只有一次,会导致不该运行的线程运行了. ...
- 多线程 线程间通信 wait,notify
1. 方法wait锁释放,notify()锁不释放
- 【原】iOS多线程之线程间通信和线程互斥
线程间通信 1> 线程间通信分为两种 主线程进入子线程(前面的方法都可以) 子线程回到主线程 2> 返回主线程 3> 代码 这个案例的思路是:当我触摸屏幕时,会在子线程加载图片,然后 ...
- C++多线程编程(三)线程间通信
多线程编程之三——线程间通讯 作者:韩耀旭 原文地址:http://www.vckbase.com/document/viewdoc/?id=1707 七.线程间通讯 一般而言,应用程序中的一个次要线 ...
- Java多线程基础——线程间通信
在使用多线程的时候,经常需要多个线程进行协作来完成一件事情.在前面两章分析了Java多线程的基本使用以及利用synchronized来实现多个线程同步调用方法或者执行代码块.但上面两章的内容涉及到的例 ...
- Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)
一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...
- Java多线程:线程间通信之volatile与sychronized
由前文Java内存模型我们熟悉了Java的内存工作模式和线程间的交互规范,本篇从应用层面讲解Java线程间通信. Java为线程间通信提供了三个相关的关键字volatile, synchronized ...
随机推荐
- UIView CALayer 的区别
UIView与CALayer的区别,很详细 研究Core Animation已经有段时间了,关于Core Animation,网上没什么好的介绍.苹果网站上有篇专门的总结性介绍,但是似乎原理性的东西不 ...
- 如何将.il、.res文件封装成dll文件
将你的.il..res文件保存在你的硬盘上,如下图: 我存放的路径在E盘的test文件夹中,我们开始封装了咯.进入DOS命令,如下图: 我们通过DOS命令先进入.il..res文件目录,如下图: 然后 ...
- Xcode添加注释
VVDocumenter-Xcode,自动生成注释,感觉比较方便的插件,分享下,应该很多人都知道= = 在 https://github.com/onevcat/VVDocumenter-Xcode ...
- qt_文本编辑器实现_附带详细注释和源码下载
源码下载: 链接: http://pan.baidu.com/s/1c21EVRy 密码: qub8 实现主要的功能有:新建,打开,保存,另存为,查找(查找的时候需要先将光标放到最下面位置才能查全,不 ...
- SYSIBM.SYSPACKSTMT db2 存储statement的表
SYSIBM.SYSPACKSTMT table The SYSIBM.SYSPACKSTMT table contains one or more rows for each statement ...
- Struts2之类型转换器
一.类型转换器的应用场景 类型转换是OGNL的一部分,默认的八种基本类型.String.Date会使用类型转换,但是更复杂的类型转换就需要我们自定义了(虽然这个东西一般根本用不到),OGNL可以应用在 ...
- JavaScript的内置对象和浏览器对象
在javascript中对象通常包括两种类型:内置对象和浏览器对象,此外,用户还可以自定义对象. 对象包含两个要素:1.用来描述对象特性的一组数据,也就是若干变量,通常称为属性.2.用来操作对象特性的 ...
- sql server 常用脚本(日常查询所需)
1:查看sql server代理中作业的运行状况的脚本 -- descr : a simple sql script to view sql server jobs run status -- las ...
- Sample Apps by Android Team -- Amazed
Sample Apps by Android Team 代码下载:http://pan.baidu.com/s/1eSNmdUE , 代码原地址:https://code.google.com/arc ...
- CLR via C#(04)- 本是同根生
一.等值性——Equals()方法 有时候我们需要比较两个对象是否相等,比如在一个ArrayList中进行排序查找等操作时. System.Object提供了Equals()虚方法: class Ob ...