08_多线程
2015-08-31 13:28
483 查看
一、基本概念
线程:是依赖于进程的执行绪(执行路径/控制单元),是程序使用CPU的基本单位。
进程:当前正在执行的程序,代表一个应用程序在内存中的执行区域。
多进程:同一时间段内执行多个任务。同一时刻只能执行一个任务。如Windows为代表的操作系统。
多进程并不提高某个程序的执行速度,仅仅是提高了CPU的使用率。真正的多进程执行是指多核同时计算。
单线程:一个进程中,只有一个线程执行。
多线程:同一个进程中,多个线程执行。这多个线程共享该进程资源(堆内存与方法区),栈内存独立,即每一个线程占用一个栈。
线程两种调度模型:
分时调度模型 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片。
抢占式调度模型 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个。(线程随机性)
Java使用的为抢占调度模型。
线程并行与线程并发
线程并行:正常的多线程执行就是线程并行。即逻辑上同一时间同时运行。
线程并发(异常):由于线程抢占而不应出现的某一时刻的线程及相关数据状态。如并发修改异常的产生。
JVM的启动支持多线程:
JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。
Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程”,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。
线程生命周期
二、线程创建方式
线程创建方式一:
继承Thread类.要覆盖其run方法,调用线程的start方法.
作用:1.启动线程
2.运行run方法。目的是将自定义的代码存储在run方法中,让线程运行
cpu每次只执行一个程序,只是在快速的不同线程间切换,表现了多线程的随机性
[java] view
plaincopy
class demo extends Thread{
public void run(){
}
}
run方法用于存储线程要运行的代码。
demo demo=new demo();创建对象就创建了一个线程。
run方法和 start方法
run方法 仅仅是对象调用方法,并没有运行线程
start方法 是开启线程并且执行线程中的run方法
创建线程的第二种方式:实现Runnable接口。
创建线程
Thread t=new Thread(new 对象名());
步骤:
1,定义类实现Runnable接口。
2,覆盖接口中的run方法(用于封装线程要运行的代码)。
3,通过Thread类创建线程对象;
4,将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。
为什么要传递呢?因为要让线程对象明确要运行的run方法所属的对象。
5,调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。
实现方式和继承方式有什么区别?
继承Thread类:线程代码块存放在Thread子类的run方法中
实现Runnable,线程代码存放在接口的子类的run方法中,可以被多实现。
继承方式有局限性。要被实现多线程的一个类 如果继承了父类 就不能再继承Thread类。
实现方式就变面了单继承的局限性。
方式一与方式二的区别
方式一:当类去描述事物,事物中有属性和行为。如果行为中有部分代码需要被多线程所执行,同时还在操作属性。就需要该类继承Thread类,产生该类的对象作为线程对象。可是这样做会导致每一个对象中都存储一份属性数据。无法在多个线程中共享该数据。加上静态,虽然实现了共享但是生命周期过长。
方式一:如果一个类明确了自己的父类,那么它就不可以再继承Thread。因为java不允许类的多继承。
方式二:将线程与运行的业务逻辑分离,可以让多个线程共享业务逻辑中的数据。
方式二:可以让业务类不再继承Thread而专注于业务继承其他类,避免了单继承的局限性。
三、多线程——Lock锁简介
相较于synchronized方式,Lock锁的出现使同步操作更为灵活。无需使用限制性强的代码块。
Lock同样为抽象类,需要使用其子类ReentrantLock的对象完成方法调用。
主要方法:
public void lock()获取锁
public void unlock() 释放锁
在多线程的代码编辑过程中,由于考虑得不够周全,会出现死锁的情况。
线程死锁代码:备注
原因分析:
线程1将锁1锁住,线程2将锁2锁住,而线程1要继续执行锁2中的代码,线程2要继续执行锁1中的代码,但是此时,两个锁均处于锁死状态。最终导致两线程相互等待,进入无限等待状态。
有同步代码块的嵌套动作。
解决方法:
不要写同步代码块嵌套。
示例代码
[java] view
plaincopy
private Lock lock=new ReentrantLock();
private Condition condition =lock.newCondition();
public void cet(String name ) throws
{
lock.lock();
try
{
while(flag)
contidition.await();
this.name=name+"--"+count++;
sop(Thread.currentThread().getName()+"...生产者..."+this.name)
flag=true;
condition.signalAll();
}
finally
{
lock.unlock();
}
}
四、多线程通信
线程间通信:多个线程在操作同一个资源,但是操作的动作不同。
1.是不是两个或两个以上的线程。解决办法 两个线程都要被同步。
2.是不是同一个锁。解决办法 找同一个对象作为锁。
等待唤醒机制。
wait后,线程就会存在线程池中,notify后就会将线程池中的线程唤醒。
notifyAll();唤醒线程池中所有的线程。
实现方法 :
给资源加个标记 flag
synchronized(r)
[java] view
plaincopy
{
while(r.flag)//多个生产者和消费者 if(r.flag)//一个生产者和消费者
r.wait();
代码
r.flag=true;
r.notify();
r.notifyAll();
}
例子:
[java] view
plaincopy
package cn.itcast.thread;
/*
* 多线程的通信
* 输入线程赋值
* 输出线程打印值
*
*/
//资源对象
class Resource{
String name;
String sex;
boolean b = false;//定义,b=true,赋值完成,b = false打印完成
}
//定义输入线程
class Input implements Runnable{
Resource r ;
Input(Resource r){this.r = r;}
public void run(){
int x = 0 ;
while(true){
synchronized(r){
//输入线程,判断b的值,如果是真,等待
if(r.b==true)
try{r.wait();}catch(Exception e){}
if(x%2==0){
r.name = "张三";
r.sex = "男";
}else{
r.name = "lisi";
r.sex = "nv";
}
x++;
//标记改成true
r.b = true;
//唤醒输出线程
r.notify();
}
}
}
}
//定义输出线程,打印变量值
class Output implements Runnable{
Resource r ;
Output(Resource r){this.r = r;}
public void run(){
while(true){
synchronized(r){
if(r.b==false)
try{r.wait();}catch(Exception e){}
System.out.println(r.name+"..."+r.sex);
r.b = false;
r.notify();
}
}
}
}
public class ThreadDemo6 {
public static void main(String[] args) {
Resource r = new Resource();
Input in = new Input(r);
Output out = new Output(r);
Thread tin = new Thread(in);
Thread tout = new Thread(out);
tin.start();
tout.start();
}
}
线程:是依赖于进程的执行绪(执行路径/控制单元),是程序使用CPU的基本单位。
进程:当前正在执行的程序,代表一个应用程序在内存中的执行区域。
多进程:同一时间段内执行多个任务。同一时刻只能执行一个任务。如Windows为代表的操作系统。
多进程并不提高某个程序的执行速度,仅仅是提高了CPU的使用率。真正的多进程执行是指多核同时计算。
单线程:一个进程中,只有一个线程执行。
多线程:同一个进程中,多个线程执行。这多个线程共享该进程资源(堆内存与方法区),栈内存独立,即每一个线程占用一个栈。
线程两种调度模型:
分时调度模型 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片。
抢占式调度模型 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个。(线程随机性)
Java使用的为抢占调度模型。
线程并行与线程并发
线程并行:正常的多线程执行就是线程并行。即逻辑上同一时间同时运行。
线程并发(异常):由于线程抢占而不应出现的某一时刻的线程及相关数据状态。如并发修改异常的产生。
JVM的启动支持多线程:
JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。
Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程”,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。
线程生命周期
二、线程创建方式
线程创建方式一:
继承Thread类.要覆盖其run方法,调用线程的start方法.
作用:1.启动线程
2.运行run方法。目的是将自定义的代码存储在run方法中,让线程运行
cpu每次只执行一个程序,只是在快速的不同线程间切换,表现了多线程的随机性
[java] view
plaincopy
class demo extends Thread{
public void run(){
}
}
run方法用于存储线程要运行的代码。
demo demo=new demo();创建对象就创建了一个线程。
run方法和 start方法
run方法 仅仅是对象调用方法,并没有运行线程
start方法 是开启线程并且执行线程中的run方法
创建线程的第二种方式:实现Runnable接口。
创建线程
Thread t=new Thread(new 对象名());
步骤:
1,定义类实现Runnable接口。
2,覆盖接口中的run方法(用于封装线程要运行的代码)。
3,通过Thread类创建线程对象;
4,将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。
为什么要传递呢?因为要让线程对象明确要运行的run方法所属的对象。
5,调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。
实现方式和继承方式有什么区别?
继承Thread类:线程代码块存放在Thread子类的run方法中
实现Runnable,线程代码存放在接口的子类的run方法中,可以被多实现。
继承方式有局限性。要被实现多线程的一个类 如果继承了父类 就不能再继承Thread类。
实现方式就变面了单继承的局限性。
方式一与方式二的区别
方式一:当类去描述事物,事物中有属性和行为。如果行为中有部分代码需要被多线程所执行,同时还在操作属性。就需要该类继承Thread类,产生该类的对象作为线程对象。可是这样做会导致每一个对象中都存储一份属性数据。无法在多个线程中共享该数据。加上静态,虽然实现了共享但是生命周期过长。
方式一:如果一个类明确了自己的父类,那么它就不可以再继承Thread。因为java不允许类的多继承。
方式二:将线程与运行的业务逻辑分离,可以让多个线程共享业务逻辑中的数据。
方式二:可以让业务类不再继承Thread而专注于业务继承其他类,避免了单继承的局限性。
三、多线程——Lock锁简介
相较于synchronized方式,Lock锁的出现使同步操作更为灵活。无需使用限制性强的代码块。
Lock同样为抽象类,需要使用其子类ReentrantLock的对象完成方法调用。
主要方法:
public void lock()获取锁
public void unlock() 释放锁
在多线程的代码编辑过程中,由于考虑得不够周全,会出现死锁的情况。
线程死锁代码:备注
原因分析:
线程1将锁1锁住,线程2将锁2锁住,而线程1要继续执行锁2中的代码,线程2要继续执行锁1中的代码,但是此时,两个锁均处于锁死状态。最终导致两线程相互等待,进入无限等待状态。
有同步代码块的嵌套动作。
解决方法:
不要写同步代码块嵌套。
示例代码
[java] view
plaincopy
private Lock lock=new ReentrantLock();
private Condition condition =lock.newCondition();
public void cet(String name ) throws
{
lock.lock();
try
{
while(flag)
contidition.await();
this.name=name+"--"+count++;
sop(Thread.currentThread().getName()+"...生产者..."+this.name)
flag=true;
condition.signalAll();
}
finally
{
lock.unlock();
}
}
四、多线程通信
线程间通信:多个线程在操作同一个资源,但是操作的动作不同。
1.是不是两个或两个以上的线程。解决办法 两个线程都要被同步。
2.是不是同一个锁。解决办法 找同一个对象作为锁。
等待唤醒机制。
wait后,线程就会存在线程池中,notify后就会将线程池中的线程唤醒。
notifyAll();唤醒线程池中所有的线程。
实现方法 :
给资源加个标记 flag
synchronized(r)
[java] view
plaincopy
{
while(r.flag)//多个生产者和消费者 if(r.flag)//一个生产者和消费者
r.wait();
代码
r.flag=true;
r.notify();
r.notifyAll();
}
例子:
[java] view
plaincopy
package cn.itcast.thread;
/*
* 多线程的通信
* 输入线程赋值
* 输出线程打印值
*
*/
//资源对象
class Resource{
String name;
String sex;
boolean b = false;//定义,b=true,赋值完成,b = false打印完成
}
//定义输入线程
class Input implements Runnable{
Resource r ;
Input(Resource r){this.r = r;}
public void run(){
int x = 0 ;
while(true){
synchronized(r){
//输入线程,判断b的值,如果是真,等待
if(r.b==true)
try{r.wait();}catch(Exception e){}
if(x%2==0){
r.name = "张三";
r.sex = "男";
}else{
r.name = "lisi";
r.sex = "nv";
}
x++;
//标记改成true
r.b = true;
//唤醒输出线程
r.notify();
}
}
}
}
//定义输出线程,打印变量值
class Output implements Runnable{
Resource r ;
Output(Resource r){this.r = r;}
public void run(){
while(true){
synchronized(r){
if(r.b==false)
try{r.wait();}catch(Exception e){}
System.out.println(r.name+"..."+r.sex);
r.b = false;
r.notify();
}
}
}
}
public class ThreadDemo6 {
public static void main(String[] args) {
Resource r = new Resource();
Input in = new Input(r);
Output out = new Output(r);
Thread tin = new Thread(in);
Thread tout = new Thread(out);
tin.start();
tout.start();
}
}
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统