A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 热工v 中级黑马   /  2016-5-6 22:36  /  636 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文


多线程:


1.1线程的概述:

线程是程序执行的一条路径, 一个进程中可以包含多条线程

         线程并发执行可以提高程序的效率, 可以同时完成多项工作


1.2多线程的应用场景:

         屏幕共享程序

         各式可多个文件同时下载的下载软件

         聊天工具软件

         同时工作的服务器软件等


2.多线程并行和并发的区别(了解就好):

以两方概述进行比对

多线程并行的概述:

         2.1.1并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)

2.1.2并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。

2.1.3比如我跟两个网友聊天,左手操作一个电脑跟甲聊,同时右手用另一台电脑跟乙聊天,这就叫并行。


多线程并发的概述:

2.2.1如果用一台电脑我先给甲发个消息,然后立刻再给乙发消息,然后再跟甲聊,再跟乙聊。这就叫并发。



3.Java程序运行原理和JVM的启动是多线程的论证:


3.1 Java程序运行原理:

Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个“主线程” ,然后主线程去调用某个类的main 方法。


3.2 JVM的启动是多线程的论证:

原理上: JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

代码证实:

public class Demo1_Thread {

Public static void main(String[] args) {

     For(int I = 0; I <100000; i++){

              New Demo();

}

For(int i = 0; I < 10000; i++){

     System.out.println(“我是主线程的执行代码”);

}

}

}

Class Demo {

Public void finalize() {

     System.out.println(“垃圾被清扫了”);

}

}






4.多线程程序实现的方法

4. 1 继承Thread

         定义类继承Thread

         重写run方法

         把新线程要做的事写在run方法中

         创建线程对象

         开启新线程, 内部会自动执行run方法


实现代码:

public static void main(String[] args) {

                   MyThreadmt = new MyThread();   

                   mt.start();

                   for(inti = 0; i < 1000; i++) {

                            System.out.println("bb");

                   }

         }

}

class MyThread extends Thread {

         publicvoid run() {

                   for(inti = 0; i < 1000; i++) {

                            System.out.println("aaaaaaaaaaaa");

                   }

         }



4.2实现Runnable

         定义类实现Runnable接口

         实现run方法

         把新线程要做的事写在run方法中

         创建自定义的Runnable的子类对象

         创建Thread对象, 传入Runnable

         调用start()开启新线程, 内部会自动调用Runnablerun()方法

实现代码:

public static void main(String[] args) {

                   MyRunnablemr = new MyRunnable();

                   //Runnabletarget = mr;  mr = 0x0011

                   Threadt = new Thread(mr);

                   t.start();

                   for(inti = 0; i < 1000; i++) {

                            System.out.println("bb");

                   }

         }

}

class MyRunnable implements Runnable {

         publicvoid run() {

                   for(inti = 0; i < 1000; i++) {

                            System.out.println("aaaaaaaaaaaa");

                   }

         }








7 个回复

倒序浏览
5.多线程(实现Runnable的原理)(了解就好):


实现原理方法: 查看源码


         5.1看Thread类的构造函数,传递了Runnable接口的引用


         5.2通过init()方法找到传递的target给成员变量的target赋值


         5.3查看run方法,发现run方法中有判断,如果target不为null就会调用Runnable接口子类对象的run方法








6.多线程(两种方法的区别:


6.1 通过查看源码的区别:


a.继承Thread : 由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法


         b.实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了它,start()调用run()方法时内部判断成员变量Runnable的引用是否为空, 不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法





6.2 两种方法分别的好处和弊端:


6.2.1继承Thread


         好处是:可以直接使用Thread类中的方法,代码简单


         弊端是:如果已经有了父类,就不能用这种方法





6.2.2实现Runnable接口


         好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的


         弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂





注:一般来说编程时会推荐使用继承Thread,因为相对来说继承Thread的运用代码会相对比较简单,而实现Runnable接口在原理上来看可以看成是继承Thread的一种补充.




7.多线程(匿名内部类实现线程的两种方式):


7.1继承Thread类


         7.1.1继承Thread类


         7.1.2重写run方法


         7.1.3将要执行的代码写在run方法中


         7.1.4开启线程


7.2实现Runnable接口


         开启线程:


         7.2.1将Runnable的子类对象传递给Thread的构造方法


         7.2.2将run方法重写


代码演示:


public static void main(String[] args) {


                   newThread() {


                            publicvoid run() {


                                     for(inti = 0; i < 1000; i++) {


                                               System.out.println("aaaaaaaaaaaaaa");


                                     }


                            }


                   }.start();   


                   newThread(new Runnable() {


                            publicvoid run() {


                                     for(inti = 0; i < 1000; i++) {


                                               System.out.println("bb");


                                     }


                            }


                   }).start();


         }





}




8.多线程(获取名字和设置名字)


8.1 获取名字


通过getName()方法获取线程对象的名字





8. 2 设置名字


通过构造函数可以传入String类型的名字





实现代码1:


public static void main(String[] args) {


                   newThread("芙蓉姐姐") {


                            publicvoid run() {


                                     System.out.println(this.getName()+ "....aaaaaaaaa");


                            }


                   }.start();


                   newThread("凤姐") {


                            publicvoid run() {


                                     System.out.println(this.getName()+ "....bb");


                            }


                   }.start();


         }


}








实现代码2:


public static void main(String[] args) {


                   Threadt1 = new Thread() {


                            publicvoid run() {


                                     System.out.println(this.getName()+ "....aaaaaaaaaaaaa");


                            }


                   };


                   Threadt2 = new Thread() {


                            publicvoid run() {


                                     System.out.println(this.getName()+ "....bb");


                            }


                   };


                   t1.setName("张三");


                   t2.setName("李四");


                   t1.start();


                   t2.start();


         }








回复 使用道具 举报
9. 多线程(获取当前线程的对象)(重点掌握):


Thread.currentThread(),主线程也可以获取.获取当前正在执行的线程.


返回当前线程方法的使用.(返回的是Thread)


实现代码:


public static void main(String[] args) {


                   newThread() {


                            publicvoid run() {


                                     System.out.println(getName()+ "....aaaaaa");


                            }


                   }.start();


                  


                  


                   newThread(new Runnable() {


                            publicvoid run() {


                                     System.out.println(Thread.currentThread().getName()+ "...bb");


                            }


                   }).start();


                  


                   Thread.currentThread().setName("我是主线程");


                   System.out.println(Thread.currentThread().getName());


         }


}








10. 多线程(休眠线程)


Thread.sleep(毫秒,纳秒), 控制当前线程休眠若干毫秒1秒= 1000毫秒 1秒 = 1000 *1000 * 1000纳秒 1000000000





实现代码1:


Public static void main(String[] args) {


         For(intI = 20; I >= 0; i--) {


                   Thread.sleep(1000);


                   System.out.println("倒计时第" +i+ "秒");


}


}


实现代码2:


public static void main(String[] args)throws InterruptedException {


                   //demo1();


                   newThread() {


                            publicvoid run() {


                                     for(inti = 0; i < 10; i++) {


                                               try{


                                                        Thread.sleep(1000);


                                               }catch (InterruptedException e) {


                                                        e.printStackTrace();


                                               }


                                               System.out.println(getName()+ "...aaaaaaaaaa");


                                     }


                            }


                   }.start();


                   newThread() {


                            publicvoid run() {


                                     for(inti = 0; i < 10; i++) {


                                               try{


                                                        Thread.sleep(1000);


                                               }catch (InterruptedException e) {


                                                        e.printStackTrace();


                                               }


                                               System.out.println(getName()+ "...bb");


                                     }


                            }


                   }.start();


         }











11.多线程(守护线程)


setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出


课上举例:象棋,守护线程相当于除了帅棋以外的其他棋子,当帅棋被吃掉之后,所有的其余棋子判输,停止一切运动.





实现代码:


public static void main(String[] args) {


                   Threadt1 = new Thread() {


                            publicvoid run() {


                                     for(inti = 0; i < 2; i++) {


                                               System.out.println(getName()+ "...aaaaaaaaaaaaaaaaaaaa");


                                     }


                            }


                   };


                   Threadt2 = new Thread() {


                            publicvoid run() {


                                     for(inti = 0; i < 50; i++) {


                                               System.out.println(getName()+ "...bb");


                                     }


                            }


                   };


                   t2.setDaemon(true);


                   t1.start();


                   t2.start();


         }


}








12.多线程之加入线程:


12.1 join(), 当前线程暂停, 等待指定的线程执行结束后,当前线程再继续


12.2 join(int), 可以等待指定的毫秒之后继续





实现代码: public static void main(String[] args) {


                   finalThread t1 = new Thread() {


                            publicvoid run() {


                                     for(inti = 0; i < 10; i++) {


                                               System.out.println(getName()+ "...aaaaaaaaaaaaa");


                                     }


                            }


                   };


                   Threadt2 = new Thread() {


                            publicvoid run() {


                                     for(inti = 0; i < 10; i++) {


                                               if(i== 2) {


                                                        try{


                                                                 //t1.join();


                                                                 t1.join(1);


                                                        }catch (InterruptedException e) {


                                                                 e.printStackTrace();


                                                        }


                                               }


                                               System.out.println(getName()+ "...bb");


                                     }


                            }


                   };


                   t1.start();


                   t2.start();


         }


}








注:插队指定的时间,时间到达之后,交替执行直至完毕








回复 使用道具 举报
还没有学啊
回复 使用道具 举报
13 多线程(礼让线程)(了解就好)


yield让出cpu





实现代码:


public static void main(String[] args) {


                   newMyThread().start();


                   newMyThread().start();


         }





}





class MyThread extends Thread {


         publicvoid run() {


                   for(inti = 1; i <= 1000; i++) {


                            if(i% 10 == 0) {


                                     Thread.yield();                             }


                            System.out.println(getName()+ "..." + i);


                   }


         }


}








14.设置线程的优先级(也是了解就好!!!):


         setPriority()设置线程的优先级





实现代码:


public static void main(String[] args) {


                   Threadt1 = new Thread(){


                            publicvoid run() {


                                     for(inti = 0; i < 100; i++) {


                                               System.out.println(getName()+ "...aaaaaaaaa" );


                                     }


                            }


                   };


                   Threadt2 = new Thread(){


                            publicvoid run() {


                                     for(inti = 0; i < 100; i++) {


                                               System.out.println(getName()+ "...bb" );


                                     }


                            }


                   };


                   t1.setPriority(Thread.MIN_PRIORITY);            //设置最小的线程优先级


                   t2.setPriority(Thread.MAX_PRIORITY);           //设置最大的线程优先级


                  


                   t1.start();


                   t2.start();


         }


}


设置最值(最大和最小)得优先级








15多线程(同步代码块)(掌握!):


         15.1同步代码块的使用情况:


                   15.1.1当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.


                  15.1.2如果两段代码是同步的, 那么同一时间只能执行一段,在一段代码没执行结束之前, 不会执行另外一段代码.





         15.2同步代码块的概述:


                   使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块


注: 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的





实现代码:


public static void main(String[] args) {


                   finalPrinter p = new Printer();


                  


                   newThread() {


                            publicvoid run() {


                                     while(true){


                                               p.print1();


                                     }


                            }


                   }.start();


                  


                   newThread() {


                            publicvoid run() {


                                     while(true){


                                               p.print2();


                                     }


                            }


                   }.start();


         }





}





class Printer {


         Demod = new Demo();


         publicvoid print1() {


                   synchronized(d){


                            System.out.print("黑");


                            System.out.print("马");


                            System.out.print("程");


                            System.out.print("序");


                            System.out.print("员");


                            System.out.print("\r\n");


                   }


         }


         


         publicvoid print2() {


                   synchronized(d){               


                            System.out.print("传");


                            System.out.print("智");


                            System.out.print("播");


                            System.out.print("客");


                            System.out.print("\r\n");


                   }


         }


}





class Demo{}





注:   1,同步代码块,锁机制,锁对象可以是任意的


2,锁对象不能使匿名对象,因为匿名对象不是同一个对象.











16.多线程(同步方法)


         使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的





注:   1,非静态同步函数的锁对象是this


         2,静态的同步函数的锁是该类的字节码对象





实现代码:


public static void main(String[] args) {


                   finalPrinter2 p = new Printer2();


                  


                   newThread() {


                            publicvoid run() {


                                     while(true){


                                               p.print1();


                                     }


                            }


                   }.start();


                  


                   newThread() {


                            publicvoid run() {


                                     while(true){


                                               p.print2();


                                     }


                            }


                   }.start();


         }





}





class Printer2 {


         Demod = new Demo();


         publicstatic synchronized void print1() {


                   System.out.print("黑");


                   System.out.print("马");


                   System.out.print("程");


                   System.out.print("序");


                   System.out.print("员");


                   System.out.print("\r\n");


         }


                  public static void print2() {


                   synchronized(Printer2.class){                  


                            System.out.print("传");


                            System.out.print("智");


                            System.out.print("播");


                            System.out.print("客");


                            System.out.print("\r\n");


                   }


         }


}








当这个方法里面所有的对象都需要同步的时候,才能使用同步方法.














回复 使用道具 举报
17. 多线程(线程安全问题)(重点掌握)





17.1多线程安全问题的概述:


17.1.1多线程并发操作同一数据时, 就有可能出现线程安全问题


17.1.2使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作





17.2通过案例学习线程安全问题(铁路售票问题):


实现代码:


public static void main(String[] args) {


                   newTicket().start();


                   newTicket().start();


                   newTicket().start();


                   newTicket().start();


         }





}





class Ticket extends Thread {


         privatestatic int ticket = 100;


         //privatestatic Object obj = new Object();


         publicvoid run() {


                   while(true){


                            synchronized(Ticket.class){


                                     if(ticket<= 0) {


                                               break;


                                     }


                                     try{


                                               Thread.sleep(10);


                                     }catch (InterruptedException e) {


                                               e.printStackTrace();


                                     }


                                     System.out.println(getName()+ "...这是第" + ticket-- + "号票");


                            }


                   }


         }


}








18. 多线程(火车站卖票的例子):


用实现Runnable接口





实现代码:


public static void main(String[] args) {


                   MyTicketmt = new MyTicket();


                   newThread(mt).start();


                   newThread(mt).start();


                   newThread(mt).start();


                   newThread(mt).start();


                  


                   /*Threadt1 = new Thread(mt);


                   t1.start();


                   t1.start();


                   t1.start();


                   t1.start();*/


         }


}


class MyTicket implements Runnable {


         privateint tickets = 100;


         @Override


         publicvoid run() {


                   while(true){


                            synchronized(this){


                                     if(tickets<= 0) {


                                               break;


                                     }


                                     try{


                                               Thread.sleep(10);


                                     }catch (InterruptedException e) {


                                               e.printStackTrace();


                                     }


                                     System.out.println(Thread.currentThread().getName()+ "...这是第" + tickets-- + "号票");


                            }


                   }


         }








注:   1,多次启动一个线程是非法的.


19. 多线程(死锁)(避免)





19.1多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁


         19.2尽量不要嵌套使用





实际代码(莫写莫作死!)


private static String s1 = "筷子左";


         privatestatic String s2 = "筷子右";





         publicstatic void main(String[] args) {


                   newThread() {


                            publicvoid run() {


                                     while(true){


                                               synchronized(s1){


                                                        System.out.println(getName()+ "...获取" + s1 + "等待" + s2);


                                                        synchronized(s2){


                                                                 System.out.println(getName()+ "...拿到" + s2 + "开吃");


                                                        }


                                               }


                                     }


                            }


                   }.start();


                  


                   newThread() {


                            publicvoid run() {


                                     while(true){


                                               synchronized(s2){


                                                        System.out.println(getName()+ "...获取" + s2 + "等待" + s1);


                                                        synchronized(s1){


                                                                 System.out.println(getName()+ "...拿到" + s1 + "开吃");


                                                        }


                                               }


                                     }


                            }


                   }.start();


         }


}








20. 多线程(以前的线程安全的类回顾)


20.1 回顾以前说过的线程安全问题:


         20.1.1看源码:Vector,StringBuffer,Hashtable,Collections.synchroinzed(xxx)


         20.1.2 Vector是线程安全的,ArrayList是线程不安全的


         20.1.3 StringBuffer是线程安全的,StringBuilder是线程不安全的


         20.1.4 Hashtable是线程安全的,HashMap是线程不安全的
回复 使用道具 举报
居然没法一次性发上来我也是整个人都不好了
回复 使用道具 举报
往上顶一个
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马