首页 > 代码库 > 黑马程序员-多线程

黑马程序员-多线程

多线程

       进程:是一个正在执行的程序           。

       线程:就是进程中的一个独立的控制单元,线程在控制进程的执行,一个进程中至少有 一个线程。

java VM 启动的时候会有一个进程java.exe。该进程中至少有一个负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之位主线程。

多线程的一个特性;随机性,谁抢到谁执行,至于执行对长,cpu说了算

创建新执行线程有两种方法。一种方法是将类声明为Thread的子类。该子类应重写Thread类的run方法。

1.如何在自定义的代码中,自定义一个线程呢?

       通过对api的查找,java已经提供了对线程这类事物的描述,就是Thread类。

       创建线程的第一种方式:继承Thread类。

       步骤:

       1.定义类继承Thread

       2.复写Thread类中的run方法

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

       3.调用线程的start方法

              该方法有两个作用:启动线程,调用run方法(存储要执行的代码)

为什么要覆盖run方法呢?

       Thread 用于描述线程。

       该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。

       也就是说Thread类中的run方法,用于存储线程要运行的代码。

线程的五种状态:

被创建:start()

冻结状态(睡眠,等待):放弃了执行资格  运行,阻塞可以到达

注:在同步代码中,wait()方法会释放锁,sleep()不会释放锁。

临时状态阻塞:具备执行资格,但没执行权  运行,冻结可以到达阻塞

运行:具备执行资格和执行权  创建,冻结,阻塞可以到达运行。

消亡:stop run()方法执行结束。运行-->消亡

创建线程的第二种方式(必须掌握);实现Runnable 接口

步骤;

1.定义类实现Runnble接口

2.覆盖Runnable接口中的run方法   

3.通过Thread类建立线程对象

4.将Runnble接口的子类对象作为实际参数传递给Thread类的构造函数;

       为什么要将Runnable接口的子类对象传递给Thread的构造函数呢?        

              因为,Thread类要运行自定义run()的方法,而自定义的run方法所属的对象是Runnable接口的子类对象

              Thread的构造函数可以接收Runnable的子类。所以要让线程去执行我们自己的run方法,就将run()所属的

              对象传入。然后Thread会去调用对象中的run(),当然这就不是我们要管的了。

5.调用Thread类的start方法开启线程

 

实现方式和继承方式有什么区别?(重要)

实现的好处是:避免了单继承的局限性,如果对象本身已经继承了一个类,则无法继承再Thread

在定义线程时,建议使用是实现的方式式

两种方式的区别;

继承;线程代码存放在Thread子类run方法中

实现;线程代码存放在Runnable接口子类的run方法中

多线程出现安全问题原因;

       当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。       如:判断-结论。判断后线程交替,等线程在回来,往往出现问题。

解决办法;

       对多条操作共享数数据的语句,只能让一个线程都执行完,在执行过程中其他线程不可以参与执行

就是同步代码块。

synchronized(对象)

{

       需要被同步的代码

}

对象如同锁,持有锁的线程可以在同步中执行。

没有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

火车上的卫生间--经典。

同步的前提;

1.必须要有两个或两个以上的线程。

2.必须是多个线程使用同一个锁。

必须保证同步中只能有一个线程在运行。

好处;解决多线程的安全问题

弊端;多线程需要判断,较为消耗资源。

如何找多线程问题;

1.明确哪些代码是多线程运行代码。、

2.明确共享数据

3.明确多线程运行代码中哪些语句是操作共享数据的。

同步函数和同步代码块

两者的区别:

同步函数的锁:同步函数所在的对象的this。

同步代码块:可以自己定义

如果同步函数被静态修饰,那么使用的锁是什么呢?本类的字节码文件

静态方法中不可以用this,静态进内存,内存中没有本类对象,

但是一定有本类对应的自节码文件对象。

单例设计模式。

*/

//饿汉式

class Single

{

       private static final Single s = new Single();

       private Single(){}

       public static Single getInstance()

       {

              return s;

       }

}

 

//懒汉式

class single

{

       private static  Single s = null;//懒汉式不可以使用final

       private Single(){}

       public static Single getInstance()//同步函数加了锁会很低效

       {//双重判断,提高点效率

              if(s==null){

                     synchrosized(Single.class)

                     {

                            if (s==null)//多条语句同时共享s

                            -->A

                            -->B,容易创建多个对象

                            s= new Single();

                     }    

              }

              return s ;       

       }

}

懒汉式与饿汉式的区别:

1.懒汉式延时加载实例对象,什么用什么时候创建对象。

2.多线程访问出现易安全问题。什么问题,判断完s==null后,容易创建多个对象。

问题怎么解决?加同步函数和同步代码块,但是很低效,每次都得判断同步,

可以使用双重判断提高效率,在同步代码块外面再次判断。

同步代码块的琐是该类的字节码文件对象,因为getInstance是静态的,没有this.

 死锁出现的原因:

 同步中嵌套同步,而锁却不同

package cn.itcast;

public class Demo22死锁 {

       /** 死锁的原因:同步中嵌套同步,而锁却不同    *  

        *  线程1拿到锁2,才释放锁1,线程2要拿到锁1,才释放锁2。 

        */

       public static void main(String[] args) {       

              new Thread(new DeadLock(false)).start();

              new Thread(new DeadLock(true)).start();

       }

}

class Lock{

       public static final Lock Lock1 = new Lock();

       public static final Lock Lock2 = new Lock();

}

class DeadLock implements Runnable{

       boolean flag = false;     

        DeadLock(boolean flag) {

              super();

              this.flag = flag;

       }    

       public void run() {

              if(flag){

                     while(true){

                      synchronized (Lock.Lock1) {

                             System.out.println("if..a");

                             synchronized (Lock.Lock2) {

                                    System.out.println("if..b");

                             }

                      }

                     }

              }

              else{

                     while(true){

                     synchronized (Lock.Lock2) {

                             System.out.println("else..a");

                      synchronized (Lock.Lock1) {

                                    System.out.println("else..b");

                             }

                      }

                     }

              }           

       }    

}