黑马程序员——总结——多线程——改1

  多线程

一、线程的概念

  线程时程序执行的控制单元,一个进程必须有一个以上的线程;多线程并发执行可以提高程序的效率,起到同时执行的效果!

  比如:电脑同时执行qq,迅雷;迅雷启动多个线程下载多个文件;窗口卖票

二、开启线程的方法

两种创建线程的方法:Extends Thread和implements Runnable

(1)、继承方法

    a,定义类继承Thread。

b,复写Thread中的run方法。

目的:将自定义代码存储在run方法中,让线程运行。

c,创建定义类的实例对象。相当于创建一个线程。

d,用该对象调用线程的start方法。该方法的作用是:启动线程,调用run方法。

 1 public class Demo2 {
 2
 3     public static void main(String[] args) {
 4         MyThread mt = new MyThread();          //4,创建自定义类的对象
 5         mt.start();                            //5,开启线程
 6
 7         for(int i = 0; i < 3000; i++) {
 8             System.out.println(Thread.currentThread().getName()+"bb");
 9         }//这个打印线程名字是main
10     }
11 }
12 class MyThread extends Thread {              //1,定义类继承Thread
13     public void run() {                      //2,重写run方法
14         for(int i = 0; i < 3000; i++) {      //3,将要执行的代码,写在run方法中
15             System.out.println(Thread.currentThread().getName()+"aaaaaaaaaaaaaaa");
16         }
17     }
18 }

(2)、实现方法

    a,定义类实现Runnable的接口。

b,覆盖Runnable接口中的run方法。目的也是为了将线程要运行的代码存放在该run方法中。

c,通过Thread类创建线程对象。

d,将Runnable接口的子类对象作为实参传递给Thread类的构造方法

 1     public static void main(String[] args) {
 2         MyThread mt = new MyThread();          //4,创建自定义类的对象
 3         Thread th=new Thread(mt);
 4         th.start();                            //5,开启线程
 5
 6         for(int i = 0; i < 3000; i++) {
 7             System.out.println(Thread.currentThread().getName()+"bb");
 8         }//这个打印线程名字是main
 9     }
10 }
11 class MyThread implements Runnable {              //1,定义类继承Thread
12     public void run() {                      //2,重写run方法
13         for(int i = 0; i < 3000; i++) {      //3,将要执行的代码,写在run方法中
14             System.out.println(Thread.currentThread().getName()+"aaaaaaaaaaaaaaa");
15         }
16     }
17 }

三、两种方法的区别

1、使用方法的区别:  

继承法:继承Thread,由于子类重写了Thread()类中run(),所以直接调用start()即可;

实现法:实现Runnable接口,构造函数中传入Runnable的引用,start()调用run ()方法是,判断成员变量Runnable的引用是否为空,

不为空编译时看的是Runnable的run(),运行时执行的是子类的run();

一般使用实现法:虽然代码较复杂,但避免了单继承的弊端,可以多实现,

2、线程的几种状态 (毕姥爷这里貌似有误,看别的资料获得)

  在Java当中,线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。 
  第一是创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。 
  第二是就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。 
  第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。 
  第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。 
  第五是死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。

3、使用匿名内部类实现线程;

继承匿名内部类法:

1 new Thread() {                                                  //1,new 类(){}继承这个类
2     public void run() {                                         //2,重写run方法
3         for(int i = 0; i < 3000; i++) {                         //3,将要执行的代码,写在run方法中
4             System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
5         }
6     }
7 }.start();

实现匿名内部类法:

1 new Thread(new Runnable(){                                      //1,new 接口(){}实现这个接口
2     public void run() {                                         //2,重写run方法
3         for(int i = 0; i < 3000; i++) {                         //3,将要执行的代码,写在run方法中
4             System.out.println("bb");
5         }
6     }
7 }).start(); 

四、同步

1、需要同步解决

  a、当多线程并发,有多段代码同时执行时,我们不希望在某一段代码执行时CPU执行权更换到其他线程

  b、如果两段代码是同步的,那么同一时间只能执行一段,完全执行完才能执行另一个线程

方法:

2、同步代码块法;关键字:synchronized加上一个所对象来定义这一段代码

        多个同步代码块使用相同的锁为对象,那么这些线程就同步了

举个栗子:

卖票:当多线程操作共享数据时,可能发生安全问题,这时我们就要把操作数据的代码同步

 1 package TEST;
 2  2 /*编写三各类Ticket、SealWindow、TicketSealCenter分别代表票信息、售票窗口、售票中心。
 3  3  * 售票中心分配一定数量的票,由若干个售票窗口进行出售,利用你所学的线程知识来模拟此售票过程。
 4  4  */
 5  5
 6  6 public class test_1Ticket {
 7  7
 8  8     public static void main(String[] args) {
 9  9
10 10         Ticket tk = new Ticket();//建立票信息对象
11 11         TicketSealCenter tsc = new TicketSealCenter(tk);// 创建售票中心。
12 12         tsc.set(200);//售票中心分配一定数量的票
13 13
14 14         new Thread(new SealWindow(tk,"一号窗口")).start();// 创建、启动线程,开始卖票。
15 15         new Thread(new SealWindow(tk,"二号窗口")).start();
16 16         new Thread(new SealWindow(tk,"三号窗口")).start();
17 17         new Thread(new SealWindow(tk,"四号窗口")).start();
18 18
19 19     }
20 20 }
21 21 class Ticket{
22 22     private static int ticket;
23 23     public static int getTicket() {
24 24         return ticket;
25 25     }
26 26     public static void setTicket(int ticket) {
27 27         Ticket.ticket = ticket;
28 28     }
29 29 }
30 30
31 31
32 32 class TicketSealCenter{
33 33     Ticket tk=null;
34 34     TicketSealCenter(Ticket tk){
35 35         this.tk=tk;
36 36     }
37 37
38 38     public void set(int t){//它可以设置票数
39 39         Ticket.setTicket(t);
40 40     }
41 41 }
42 42
43 43 class SealWindow implements Runnable{
44 44     private String name=null;
45 45     private Ticket ticket;
46 46     SealWindow(Ticket ticket,String name){
47 47         this.name=name;
48 48         this.ticket=ticket;
49 49     }
50 50     public void run(){
51 51         while(true){
52 52             synchronized (ticket) {
53 53                 int t=ticket.getTicket();
54 54                 if(t>0){
55 55                     System.out.println(name+": 第"+(t--)+"张票已卖出");
56 56                     ticket.setTicket(t);// 设置余票信息。
57 57                 }else{
58 58                     System.out.println(name+": 票已售完");//票数为0.
59 59                     break;// 退出循环。
60 60                 }
61 61             }
62 62         }
63 63     }
64 64 }

  同步修饰方法:

  使用synchronized关键字谢谢方法,该方法的代码就同步了

  注意这里的锁同步代码块直接写出来,而synchronized

  非静态同步函数的锁是:this;静态的同步函数的锁是:字节码对象

 1 class Printer {
 2     public static void print1() {
 3         synchronized(Printer.class){                //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
 4             System.out.print("黑");
 5             System.out.print("马");
 6             System.out.print("程");
 7             System.out.print("序");
 8             System.out.print("员");
 9             System.out.print("\r\n");
10         }
11     }
12     /*
13      * 非静态同步函数的锁是:this
14      * 静态的同步函数的锁是:字节码对象
15      */
16     public static synchronized void print2() {
17         System.out.print("传");
18         System.out.print("智");
19         System.out.print("播");
20         System.out.print("客");
21         System.out.print("\r\n");
22     }
23 }

注:1、多线程同步需要做到:使用同一个锁;

  2、同步解决安全问题,但消耗资料;

**注****同步方法被静态修饰后的锁,因为静态中不能存在this,那时什么?是类名.class.

同步的懒汉式单例设计模式,因为只有懒汉式才多语句影响共享数据

 1 class Single  {
 2     private static Single s = null;
 3     private Single(){}
 4     public static Single getInstance(){
 5         if(s==null) {
 6             synchronized(Single.class){
 7                 if(s==null)
 8                     s = new Single();
 9             }
10         }
11         return s;
12     }
13 }  

4、死锁问题

*多线程同步时候,如果同步代码嵌套,使用同一的锁,就可能死锁

***所以不能嵌套同步

时间: 2024-08-09 10:39:08

黑马程序员——总结——多线程——改1的相关文章

黑马程序员_多线程

------- android培训.java培训.期待与您交流! ---------- 多线程1.进程: 正在运行的程序所占有的内存空间,叫做进程. 线程: 一个应用程序中的子程序,对于CPU,子程序可以有一条独立的执行路径,称为线程. 线程特点:依靠一个应用程序,对于其他子程序,独立被CPU执行的2.多线程的好处: 充分利用CPU的资源,程序的同时运行,提高效率3.java中线程创建的两种方法: 第一种: 定义类继承Thread class extends Thread 重写Thread中的r

黑马程序员——Java多线程基础知识2

多线程协同 线程间的通讯:我们对资源的操作动作不同,比如说两个卡车一个拉煤一个装煤.但是他们共享了一个资源. 怎么样把这个资源拿出来?怎样把车装满?这个资源当然是一个类,他里面的组成元素就是对象!!现在我们就要有操作对象的思想了,我用对象把这车装满,现在一车装一个对象. 等待唤醒机制: 用的不是sleep是wait.flag标记,这是两人沟通的方式.其实每个标记就要做一次等待或者notify,判断wait,改值notify.线程池.notify唤醒里面的线程,按顺序唤醒.wait和notify必

黑马程序员___多线程小结

----------- android培训.java培训.java学习型技术博客.期待与您交流! --------- 进程和线程 进程是正在进行中的程序,指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程. Java程序的进程里有几个线程:主线程, 垃圾回收线程(后台线程) 线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据.多线程:在同一个进程中同时运行的多个任务;一个进程至少有一个线程,为了提高效率,可以在一个进程中

黑马程序员---Java多线程

---------------------- Android开发.java培训.期待与您交流! ---------------------- 线程与进程是程序运行中体现的两个名词,它包含这不同的程序域.进程指的是一个正在运行的程序,如:360,QQ运行时就是不同的两个进程.当你打开windows任务管理器时,看到的每个进程就是此时windows中正在运行的程序.线程则就是进程中的一个个独立的控制单元,线程控制着进程的执行,也就是说每个正在运行的程序中就包括着很多的线程. 主线程:Java虚拟机运

黑马程序员_Java多线程

- - - - - android培训.java培训.期待与您交流! - - - - - - 进程:正在进行中的程序.其实进程就是一个应用程序运行时的内存分配空间.进程负责的是应用程序的空间的标示. 线程:其实就是进程中一个程序执行控制单元,一条执行路径.线程负责的是应用程序的执行顺序. 一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序. 每个线程在栈区中都有自己的执行空间,自己的方法区.自己的变量. jvm在启动的时,首先有一个主线程,负责程序的执行,

黑马程序员——java多线程基础知识1

多线程 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行.jvm启动的时候会有一个进程就叫做java,exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为主线程.虚拟机至少也有两个线程,一个主线程执行,另一个负

黑马程序员——Java多线程

多线程基础知识 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行..jvm启动的时候会有一个进程就叫做java.exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为住线程.虚拟机至少也有两个线程,一个主线程执行

黑马程序员__多线程

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 1.线程是程序执行的一条路径, 一个进程中可以包含多条线程,多线程并发执行可以提高程序的效率, 可以同时完成多项工作. 2.开启新线程的两种方式 1).继承Thread [java] view plaincopy public stati

黑马程序员_多线程总结

/**多线程概述:什么是多线程? 首先,什么是进程? 进程是系统分配资源的基本单位,对于windows系统而言. 进程是程序的一次运行. 一个进程中至少有一个线程存在,因为线程才是实际运行单元. 线程:是指程序中的控制单元,一条执行路径. 一个程序可以有多线程并发执行,每个线程是一个控制单元.一个程序可以有多条执行线路, 每个执行线路代表一个线程. 线程的创建是由底层系统完成的,对于Java中的线程是jvm通过调用底层的windows操作系统的功能创建的. 注意一个线程在程序上的体现和内存中体现