Java基础——多线程
2014-11-27 16:52
218 查看
多线程
进程:正在运行的程序,一个进程中至少有一个线程线程:线程就是进程中的一个控制单元,线程控制着进程的执行
多线程:每个线程在“同时”运行,是因为cpu在做着快读的切换,以达到同时运行的效果
体现:程序主线程在执行,垃圾回收也在执行,这是多线程的体现
1.Thread(继承类)
字段摘要 | |
---|---|
static int | MAX_PRIORITY 线程可以具有的最高优先级。10 |
static int | MIN_PRIORITY 线程可以具有的最低优先级。5 |
static int | NORM_PRIORITY 分配给线程的默认优先级。1 |
构造方法摘要 |
---|
Thread() 分配新的 Thread对象。 |
Thread(Runnable target) 分配新的 Thread对象。 |
Thread(Runnable target, String name) 分配新的 Thread对象。 |
Thread(String name) 分配新的 Thread对象。 |
方法摘要 |
---|
static Thread | currentThread() 返回对当前正在执行的线程对象的引用。 |
long | getId() 返回该线程的标识符。 |
String | getName() 返回该线程的名称。 |
int | getPriority() 返回线程的优先级。 |
Thread.State | getStat() 返回该线程的状态。 |
void | setName(String name) 改变线程名称,使之与参数 name相同。 |
void | interrupt() 中断线程。对线程冻结状态进行清除,强制让线程恢复到状态中来,可以操作标记让线程结束 |
void | setDaemon(boolean on) 将该线程标记为守护线程或用户线程。当前台线程都结束后,守护线程自动结束(后台线程) |
void | join() 等待该线程终止。获得主线程执行权,等待该线程终止,主线程才执行。只有main方法叫主线程。 throws InterruptedException |
String | toString() 返回该线程的字符串表示形式,包括线程名称、优先级和线程组。 |
void | setPriority(int newPriority) 更改线程的优先级。所有线程优先级默认为5 |
static void | yield() 暂停当前正在执行的线程。临时释放线程的执行权 |
1.1 要点:
(1)步骤:Thread子类需要重写run()方法,运行run()方法可通过start()方法。此时Java进程下就有两个线程了,主线程和我们创建的线程(2)run方法:其就是一个存储器,存储线程要运行的代码
(3)start方法:开启新线程并运行。不用start()方法运行run()方法,程序还是单线程
(4)分析:运行结果每一次都不一样,因为多个线程都在争抢cpu执行权,不过每一时刻只能有一个线程在执行(多核除外)
/** *需求:站台售票实例,通过继承实现多线程 *思路:因为要多个对象共享票的数量,需要对票数进行静态修饰 */ class ticket extends Thread { private static int tic = 100;//票数 public ticket(String stageName){//站台名 super(stageName); } public void run(){//线程的方法体 while(true) if(tic>0) System.out.println(Thread.currentThread().getName()+"....还剩"+tic--+"张票"); //System.out.println("票已经售完"); } } class java { public static void main(String[] args){ new ticket("站台1").start(); new ticket("站台2").start(); new ticket("站台3").start(); new ticket("站台4").start(); } }
1.2 线程运行的状态
(1)被创建:待运行(2)运行:拥有运行资格以及执行权
(3)冻结:放弃了运行资格
(4)阻塞:拥有运行资格却没有执行权
(5)消亡:没有运行资格
2.Runnable(实现接口)
方法摘要 | |
---|---|
void | run() 使用实现接口 Runnable的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run方法。 |
2.1 步骤
class MyThread implements Runnable { public void run(){ //多线程要执行的方法体; System.out.println(Thread.currentThread().getName()); } } class java { public static void main(String[] args){ //建立自定义线程类对象 Runnable r = new MyThread(); //建立线程类,并通过Thread(Runnable r)来传入自定义线程类对象 Thread t1 = new Thread(r); Thread t2 = new Thread(r); //运行多线程 t1.start(); t2.start(); //简易写法 new Thread(r).start();
2.2 特点
(1)好处:Java只支持单继承,如果该类已经是一个体系中子类,那么不能够运用继承来实现该类方法的多线程形式(2)现状:实现方式最常用
3. 线程的安全
3.1 问题产生原因
(1)重要:当多条语句在操作同一个线程的共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误3.2 问题的解决(synchronized——同步)
(1)同步代码格式如下//同步代码块格式 synchronized(对象){//对象为任意对象 需要被同步的代码块 } //同步函数格式 synchronized 作为函数的修饰符(2)同步的含义:同步就是确保同一时间段内只有一个线程能访问这段代码
(3)同步的前提
<1>.必须要有一个或两个以上的线程
<2>.必须是多个线程共同使用一把锁、监视器(锁就是对象,每一把锁都有自己的状态值,每进去一个线程此状态值都会变化)
(4)注意:同步较为消耗资源,所以尽可能减少判断的同步的次数,同步尽可能少的代码
(5)同步函数的要点
<1>.同步函数使用的锁是 this
<2>.静态同步函数使用的锁是 类名.class(字节码文件对象)
(6)死锁:同步嵌套同步,而且必须互相调用时,可能会发生。代码如下:
//死锁实现 //死锁类,自定义线程类 class DeadLock implements Runnable { private boolean flag;//标记 DeadLock(boolean flag){ this.flag = flag; } public void run(){ if(flag) synchronized(MyLock.locka){//死锁嵌套形式 System.out.println(Thread.currentThread().getName()+"......locka"); synchronized(MyLock.lockb){ System.out.println(Thread.currentThread().getName()+"......lockb"); } } else synchronized(MyLock.lockb){ System.out.println(Thread.currentThread().getName()+"......lockb"); synchronized(MyLock.locka){ System.out.println(Thread.currentThread().getName()+"......locka"); } } } } //提供锁的类 class MyLock { public static Object locka = new Object(); public static Object lockb = new Object(); } class java { public static void main(String[] args){ new Thread(new DeadLock(true)).start();//多线程的简便写法,会创建两个定义一线程类对象 new Thread(new DeadLock(false)).start(); } }
4.线程间通信
4.1 情况阐述:
(1)多个线程中每个线程运行的代码都不同4.2 等待唤醒机制
(1)方法摘要(Object类)方法摘要 | |
---|---|
void | wait() 在其他线程调用此对象的 notify()方法或 notifyAll()方法前,导致当前线程等待。throws InterruptedException |
void | notify() 唤醒在此对象监视器上等待的单个线程。 |
void | notifyAll() 唤醒在此对象监视器上等待的所有线程。 |
void | wait(long timeout) 在其他线程调用此对象的 notify()方法或 notifyAll()方法,或者超过指定的时间量前,导致当前线程等待。throws InterruptedException |
<1>.操作这些方法的对象是同步中的锁对象,因为可以通过监视器来确定线程。只有在同步中才能使用这些方法
<2>.等待和唤醒必须是同一把锁,只有同一把锁的等待线程能被同一把锁的notify唤醒
<3>.因为锁可以是任意对象,所以这些方法定义在Object类中
(3)输入和输出的代码体现(繁琐代码)————wait()、notify()的应用
/** *需求:等待唤醒机制通过输入输出的形式体现。只适合两个线程,一个输入一个输出 *思路:1.建立资源类,输入类,输出类 * 2.输入类、输出类是多线程的实现类,并且分别用一个线程来控制其输入输出过程 * 3.同步解决线程完全问题、等待唤醒机制实现输入一次输出一次的形式 */ class Res { String name; String sex; boolean b = false;//等待唤醒的判断依据 } class Input implements Runnable { //资源类的引用 Res r; //保证传入对象唯一 Input(Res r){ this.r = r; } public void run(){ int x = 0;//自定义的判断条件 while(true){ synchronized(r){ if(r.b) try{r.wait();}catch(Exception e){}//等待机制 if(x==0){ r.name="张欣"; r.sex="女";//输入 } else{ r.name="Tom"; r.sex="man"; } x = (x+1)%2;//通过此运算x的值始终为0或1 r.notify();//唤醒机制 r.b = true; } } } } class Output implements Runnable { //同上 Res r; Output(Res r){ this.r = r; } public void run(){ while(true){ synchronized(r){ if(!r.b) try{r.wait();}catch(Exception e){}//等待机制 System.out.println(r.name+"......"+r.sex);//输出 r.notify(); r.b = false; } } } } class java { public static void main(String[] args){ Res r = new Res();//建立唯一的资源类对象 new Thread(new Input(r)).start(); new Thread(new Output(r)).start();//运行多线程 } }(4)生产者和消费者的代码体现(简化代码)————while多次判断标记、nitifyAll()唤醒全部等待线程
/** *需求:用生产者消费者的形式来实现线程通信(有超过两个线程操作程序) *思路;1.建立资源类、生产者类、消费者类 * 2.资源类中建立生产消费的函数,来被生产者消费者调用 * 3.用同步解决线程安全问题,用等待唤醒全部机制保证生产一个消费一个 */ class Resource { private String name;//商品名称 private int count;//商品序号 private boolean flag = false;//判断等待唤醒的标记 Resource(String name){ this.name = name; } //生产函数 public synchronized void pdt(){ while(flag)//多次判断标记 try{wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...生产者..."+(++count)+"."+name);//生产一个商品,每生产一个序号+1 flag = true; notifyAll();//唤醒全部等待线程 } //销售函数 public synchronized void sell(){ while(!flag) try{wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...消费者........."+count+"."+name);//销售一个商品 flag = false; notifyAll(); } } class Produce implements Runnable { private Resource res;//资源引用 Produce(Resource res){//保证资源对象唯一 this.res = res; } //多线程run方法,存放生产的过程 public void run(){ while(true){ res.pdt(); } } } class Customer implements Runnable { private Resource res;//资源引用 Customer(Resource res){//保证对象唯一 this.res = res; } //多线程run方法,存放销售的过程 public void run(){ while(true){ res.sell(); } } } class java { public static void main(String[] args){ //建立要用的唯一资源对象 Resource res = new Resource("手办"); //建立两个生产线程 new Thread(new Produce(res)).start(); new Thread(new Produce(res)).start(); //建立两个销售线程 new Thread(new Customer(res)).start(); new Thread(new Customer(res)).start(); } } 类 ReentrantLock
5. JDK5.0升级
5.1 知识
(1)JDK5.0升级后多线程的同步与等待唤醒机制被替代,工具包位置为 java.util.concurrent.locks(2)synchronized关键字的功能被lock接口子类ReentrantLock中的方法替代,wait()、nitify()、notifyAll()被Condition接口子类 中的方法所替代
5.2 类概要
Lock接口(常用子类——ReentrantLock)方法摘要 | |
---|---|
void | lock() 获取锁。 |
void | unlock() 释放锁。 |
Condition | newCondition() 返回绑定到此 Lock实例的新 Condition实例。 |
方法摘要 | |
---|---|
void | await() 造成当前线程在接到信号或被中断之前一直处于等待状态。throws InterruptedException |
void | signal() 唤醒一个等待线程。 |
void | signalAll() 唤醒所有等待线程。 |
5.3 实现代码(实现本方只唤醒对方的操作,上边生产者消费者代码的转型)
/** *需求:用JDK5.0新特性实现生产者和消费者线程通信 *思路;1.建立资源类、生产者类、消费者类 * 2.资源类中建立生产消费的函数,来被生产者消费者调用 * 3.用同步解决线程安全问题,用等待唤醒全部机制保证生产一个消费一个 */ import java.util.concurrent.locks.*; class Resource { private String name;//商品名称 private int count;//商品序号 private boolean flag = false;//判断等待唤醒的标记 private Lock lock = new ReentrantLock();//同步对象 private Condition conditionPro = lock.newCondition();//锁对象 private Condition conditionCus = lock.newCondition(); Resource(String name){ this.name = name; } //生产函数 public void pdt(){ lock.lock();//锁住 try{ while(flag)//多次判断标记 conditionPro.await(); System.out.println(Thread.currentThread().getName()+"...生产者..."+(++count)+"."+name);//生产一个商品,每生产一个序号+1 flag = true; conditionCus.signalAll();//指定唤醒哪些线程 }catch(Exception e){} finally{ lock.unlock();//释放锁 } } //销售函数 public void sell(){ lock.lock(); try{ while(!flag) conditionCus.await(); System.out.println(Thread.currentThread().getName()+"...消费者........."+count+"."+name);//销售一个商品 flag = false; conditionPro.signalAll(); }catch(Exception e){} finally{ lock.unlock();//释放锁 } } } class Produce implements Runnable { private Resource res;//资源引用 Produce(Resource res){//保证资源对象唯一 this.res = res; } //多线程run方法,存放生产的过程 public void run(){ while(true){ res.pdt(); } } } class Customer implements Runnable { private Resource res;//资源引用 Customer(Resource res){//保证对象唯一 this.res = res; } //多线程run方法,存放销售的过程 public void run(){ while(true){ res.sell(); } } } class java { public static void main(String[] args){ //建立要用的唯一资源对象 Resource res = new Resource("手办"); //建立两个生产线程 new Thread(new Produce(res)).start(); new Thread(new Produce(res)).start(); //建立两个销售线程 new Thread(new Customer(res)).start(); new Thread(new Customer(res)).start(); } }
知识点:当多个不操作共享数据的程序运行时,分别定义多线程效率较高,可以使用匿名内部类的方式
相关文章推荐
- Java多线程编程基础之线程对象
- java多线程基础
- java基础巩固训练营【第一轮】(十) 多线程 补充
- java多线程开发基础
- JAVA多线程编程基础1
- Java多线程基础知识
- 学习笔记7—Java基础5_多线程
- [零基础学JAVA]Java SE应用部分-25.多线程(03) 推荐
- [零基础学JAVA]Java SE应用部分-24.多线程(02) 推荐
- java基础——多线程
- java多线程基础
- 如何使用Java编写多线程程序-Java基础-Java-编程开发
- Java多线程编程基础
- [零基础学JAVA]Java SE应用部分-26.多线程(04) 推荐
- Java多线程程序设计入门-Java基础-Java-编程开发
- java多线程 基础(二) Thread Runnable
- java多线程基础
- 浅析Java多线程程序设计机制-Java基础-Java-编程开发
- Java基础很重要(四)---多线程
- Java多线程基础