黑马程序员__多线程
来源:互联网 发布:欧洲人 野蛮 知乎 编辑:程序博客网 时间:2024/04/28 15:43
黑马程序员——多线程
------- android培训、java培训、期待与您交流! ----------
1.进程和线程的概念
进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径或者叫一个控制单元。
线程:是进程中的一个独立的控制单元,在控制着进程的执行。
总之,一个进程中至少有一个线程。
2.自定义线程的方式
(1)继承Thread类,覆盖run方法。
步骤:<1>定义类继承Thread,目的是将自定义的代码存储在run方法中让线程运行。
<2>覆写Thread类中的run方法,该方法有两个作用:启动线程和调用run方法。
代码示例:
//创建线程的第一种方式//需求:创建两个线程,和主线程交替进行class Demo extends Thread{public Demo(String name){super(name);}//覆盖run方法public void run(){for(int i=0;i<50;i++){System.out.println(this.getName()+"在运行......."+i);}}}class ThreadDemo {public static void main(String[] args) {//创建线程对象Demo d1=new Demo("线程一");Demo d2=new Demo("线程二");d1.start();d2.start();for(int i=0;i<50;i++){System.out.println("主线程在运行........."+i);}}}
(2)实现Runnable接口
步骤:<1>定义类实现Runnable接口;
<2>覆盖Runnable接口中的run方法;
<3>通过Thread类建立线程对象;
<4>将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数;
<5>调用Thread类的start()方法启动线程并调用Runnable接口子类的run方法。
代码示例:
/*需求:简单的买票程序,多个窗口同时买票。*/class SaleTicket implements Runnable{private int ticket=100;//覆盖run方法public void run(){while(true){if(ticket>0){try{Thread.sleep(10);}catch(Exception e){System.out.println(Thread.currentThread().getName()+"-----Exception------");}System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");}}}}class SaleTicketDemo2{public static void main(String[] args) {//创建Runnable子类的实例对象SaleTicket st=new SaleTicket();//创造线程对象,将Runnable子类的实例对象作为参数进行传递Thread t1=new Thread(st);Thread t2=new Thread(st);Thread t3=new Thread(st);//启动线程t1.start();t2.start();t3.start();}}
以上两种方式,实现接口的方式避免了单继承的局限性,所以在定义线程时,建议使用实现接口的方式。
3.线程的运行状态:
如下图所示:
4.多线程安全问题
出现此问题的原因:当多条语句在操作同一个线程中的共享数据时,一个线程多条语句只执行了一部分,还没有执行完时,另一个线程参与进来执行。从而导致了共享数据的错误。
解决方法有两种:同步代码块或者同步方法。
(1)同步代码块:synchronized(对象){需要被同步的代码;}
代码示例:
/*需求:简单的买票程序,多个窗口同时买票。*/class SaleTicket implements Runnable{private int ticket=100;Object obj=new Object();public void run(){while(true){//同步代码块synchronized(obj){if(ticket>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");}}}}}class SaleTicketDemo3{public static void main(String[] args) {SaleTicket st=new SaleTicket();Thread t1=new Thread(st);Thread t2=new Thread(st);Thread t3=new Thread(st);t1.start();t2.start();t3.start();}}
(2)同步方法:只需要将方法进行同步就可以。
代码示例:
/*同步代码块与同步函数互相切换。*/class SaleTicket implements Runnable{private int ticket=100;//定义标记用于切换boolean flag=true;public void run(){if(flag){while(true){//同步代码块synchronized(this){if(ticket>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");}}}}elsewhile(true)method();}//同步方法public synchronized void method(){if(ticket>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");}}}class SaleTicketDemo4{public static void main(String[] args) {SaleTicket st=new SaleTicket();Thread t1=new Thread(st);Thread t2=new Thread(st);t1.start();try{Thread.currentThread().sleep(10);}catch(Exception e){System.out.println(Thread.currentThread().getName()+"-----Exception------");}st.flag=false;t2.start();}
注意:同步的前提条件:
<1>必须要有两个或者两个以上的线程;
<2>必须是多个线程使用同一个锁;
<3>必须保证同步中只能有一个线程在运行;
同步的好处:解决了多线程的安全问题
同步的弊端:多个线程需要判断对象锁,较为浪费资源。
静态同步方法使用的对象锁是该方法所在类的字节码文件对象,即类名.class.
代码实例:
class SaleTicket implements Runnable{ private static int ticket=100; //定义标记用于切换 boolean flag=true; public void run() { if(flag) { while(true) { //同步代码块 synchronized(SaleTicket.class) { if(ticket>0){ try{ Thread.sleep(10); } catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票"); } } } } else while(true) method(); } //静态同步方法 public static synchronized void method() { if(ticket>0){ try{ Thread.sleep(10); } catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票"); } }}class SaleTicketDemo5{ public static void main(String[] args) { SaleTicket st=new SaleTicket(); Thread t1=new Thread(st); Thread t2=new Thread(st); t1.start(); try{ Thread.currentThread().sleep(10); } catch(Exception e) { } st.flag=false; t2.start(); }}
5.线程间的通信
线程间的通信其实就是多个线程在操作同一个资源,但是操作的动作不同。
代码示例:
//线程之间的通信,通过等待唤醒机制来实现class Information{ private String name; private String sex; boolean flag=false; //同步方法 public synchronized void set(String name,String sex) { //判断标记,如果为真表示已经赋值,应该等待被打印 if(this.flag) { try{ this.wait(); } catch(Exception e){} } //赋值 this.name=name; this.sex=sex; //改变标记,表示赋值成功 this.flag=true; //唤醒等待的线程 this.notify(); } public synchronized void get() { //判断标记,如果为假,表示未被赋值,应该等待被赋值 if(!this.flag) { try { this.wait(); } catch(Exception e) {
System.out.println(Thread.currentThread().getName()+".......Exception...."); } } System.out.println(name+"----"+sex); //改变标记,表示打印完毕 this.flag=false; //唤醒等待的线程 this.notify(); }}//赋值线程类class Input implements Runnable{ private Information infor; public Input(Information infor) { this.infor=infor; } public void run() { boolean flag=true; while(true) { if(flag) {
//调用方法,完成赋值操作 infor.set("Apple","girl"); flag=false; } else { infor.set("小明","男孩"); flag=true; } } }} //输出线程类class Output implements Runnable{ private Information infor; public Output(Information infor) { this.infor=infor; } public void run() { while(true) {
//调用方法完成输出操作 infor.get(); } }}class ThreadComDemo { public static void main(String[] args) { Information infor=new Information(); new Thread(new Input(infor)).start(); new Thread(new Output(infor)).start(); }}
6.生产者与消费者模型
使用同步方法的形式来实现:
代码示例:
//多个生产者与消费者class ProCusDemo {public static void main(String[] args) {Resource r=new Resource();Producer pro=new Producer(r);Consumer con=new Consumer(r);Thread t1=new Thread(pro);Thread t2=new Thread(pro);Thread t3=new Thread(pro);Thread t11=new Thread(con);Thread t22=new Thread(con);Thread t33=new Thread(con);t1.start();t2.start();t3.start();t11.start();t22.start();t33.start();}}class Resource{private String name;private int count=1;private boolean flag=false;public synchronized void set(String name){//循环判断标记while(flag){try{wait();}catch (Exception e){
System.out.println("线程被终止!!!!!!");
}}this.name=name+"--"+count++;System.out.println(Thread.currentThread().getName()+"---生产者----"+this.name);flag=true;//唤醒所有this.notifyAll();}public synchronized void out(){//循环判断while(!flag){try{wait();}catch (Exception e){
System.out.println("线程被终止!!!!!!");
}}System.out.println(Thread.currentThread().getName()+"---消费者----"+this.name);flag=false;//唤醒所有this.notifyAll();}}//生产者class Producer implements Runnable{private Resource res;Producer(Resource res){this.res=res;}public void run(){while(true){res.set("+商品+");}}}class Consumer implements Runnable{private Resource res;Consumer(Resource res){this.res=res;}public void run(){while(true){res.out();}}}
JDK1.5中提供了多线程升级的解决方案:
代码示例:
import java.util.concurrent.locks.*;//多个生产者与消费者class ProCusDemo2 {public static void main(String[] args) {Resource r=new Resource();Producer pro=new Producer(r);Consumer con=new Consumer(r);Thread t1=new Thread(pro);Thread t2=new Thread(pro);Thread t3=new Thread(pro);Thread t11=new Thread(con);Thread t22=new Thread(con);Thread t33=new Thread(con);t1.start();t2.start();t3.start();t11.start();t22.start();t33.start();}}class Resource{private String name;private int count=1;private boolean flag=false;private Lock lock=new ReentrantLock();private Condition pro_condition=lock.newCondition();private Condition con_condition=lock.newCondition();public void set(String name){lock.lock();try{//循环判断标记while(flag)//生产者线程等待pro_condition.await();this.name=name+"--"+count++;System.out.println(Thread.currentThread().getName()+"---生产者----"+this.name);flag=true;//唤醒消费者线程con_condition.signalAll();}catch(InterruptedException e){System.out.println("线程被终止!!!!!!");}finally{//释放锁lock.unlock();}}public void out(){lock.lock();try{//循环判断while(!flag)//消费者线程等待con_condition.await();System.out.println(Thread.currentThread().getName()+"---消费者----"+this.name);flag=false;//唤醒生产者线程pro_condition.signalAll();}catch (InterruptedException e){System.out.println("线程被终止!!!!!!");}finally{lock.unlock();}}}//生产者class Producer implements Runnable{private Resource res;Producer(Resource res){this.res=res;}public void run(){while(true){res.set("+商品+");}}}class Consumer implements Runnable{private Resource res;Consumer(Resource res){this.res=res;}public void run(){while(true){res.out();}}}
升级之后的解决方案,显示的对象所机制、显示的等待唤醒机制,一个锁可以对应多个Condition对象,可以实现在唤醒对方锁的同时不用唤醒己方锁,较之前的解决方案更好一些。
7.停止线程。
解决思路:结束run方法。当开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
代码示例:
class Test implements Runnable{private boolean flag=true;public void run(){while(flag){System.out.println(Thread.currentThread().getName()+"...run");}}public void changeflag(){flag=false;}}class StopThreadDemo {public static void main(String[] args) {Test test=new Test();Thread t1=new Thread(test);Thread t2=new Thread(test);t1.start();t2.start();int number=0;while(true){if(number==50){test.changeflag();break;}number++;System.out.println(Thread.currentThread().getName()+"...run");}}}
特殊情况:当线程处于冻结状态,就不会读取到标记,此时可以通过调用interrupt()方法将处于冻结状态的线程强制恢复到运行状态。
代码示例:
class Test implements Runnable{private boolean flag=true;public synchronized void run(){while(flag){try{wait();}catch (InterruptedException e){System.out.println(Thread.currentThread().getName()+"...Excption");flag=false;}System.out.println(Thread.currentThread().getName()+"...run");}}}class StopThreadDemo2 {public static void main(String[] args) {Test test=new Test();Thread t1=new Thread(test);Thread t2=new Thread(test);t1.start();t2.start();int number=0;while(true){if(number==50){//清除线程的冻结状态t1.interrupt();t2.interrupt();break;}number++;System.out.println(Thread.currentThread().getName()+"...run");}}}
8.线程池
使用线程池来执行线程任务的步骤如下:
(1)调用Executors类的静态方法创建一个ExecutorsService对象,该对象就代表一个线程池。
(2)创建Runnable实现类的实例,作为线程执行任务。
(3)调用ExecutorsService对象的submit()方法来提交Runnable示例。
(4)当不想提交任何任务时,调用ExecutorsService对象的shutdown()方法来关闭线程池。
代码示例:
import java.util.concurrent.*;class ThreadPoolDemo {public static void main(String[] args) throws Exception{//创建一个具有固定线程数的线程池ExecutorService pool=Executors.newFixedThreadPool(5);//向线程池中提交两个线程 pool.submit(new Demo()); pool.submit(new Demo());//关闭线程池pool.shutdown();}}//线程任务类class Demo implements Runnable{public void run(){for(int i=0;i<100;i++){System.out.println(Thread.currentThread().getName()+"----"+i+"-------");}}}
------- android培训、java培训、期待与您交流! ----------
- 黑马程序员__多线程
- 黑马程序员__多线程
- 黑马程序员__多线程
- 黑马程序员__多线程
- 黑马程序员__多线程
- 黑马程序员__多线程
- 黑马程序员__多线程1
- 黑马程序员__多线程2
- 黑马程序员__Java基础__多线程
- 黑马程序员__JAVA基础__多线程
- 黑马程序员Java基础__多线程
- 黑马程序员__多线程总结1
- 黑马程序员学习总结__多线程
- 黑马程序员__java基础__多线程
- [黑马程序员]多线程__蛋疼的死锁
- 黑马程序员——Java基础__多线程(上)
- 黑马程序员——Java基础__多线程(下)
- 黑马程序员__俄罗斯方块
- 3/6/2015
- (算法设计与分析)归并分类与快速分类平均时间之比较 (验证型实验)
- 【C++ Primer】【学习笔记】【第九章】顺序容器之:迭代器和迭代器范围
- HDU1811Rank of Tetris(并查集+拓扑排序)
- mysql类名不能是关键字,出现cannot insert错误
- 黑马程序员__多线程
- (算法设计与分析)用动态规划法求解资源分配问题 (验证型实验)
- Hashpmap的原理,HashMap怎样保证key的唯一性
- [线段树] HDU 1754 - I Hate It
- centos6.5安装完oracle后,$ORACLE_HOME/network/admin/目录下没有listener.ora等3个文件
- PAT A 1005. Spell It Right
- nyoj 199 无线网络覆盖
- 模板方法模式
- ios开发-c语言之流程控制中if的学习