黑马程序员_多线程(一)

来源:互联网 发布:java调用mondodb的sum 编辑:程序博客网 时间:2024/06/07 02:46
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
多线程

一、多线程概述
进程:
是正在执行的程序。
是应用程序运行时的内存分配空间。
线程:
进程中的一个程序执行控制单元。
线程负责应用程序的执行顺序。
一个进程至少有一个进程。
多线程:
当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序。

二、创建线程的方式
创建线程的第一种方式,继承Thread类
步骤:1、定义类继承Thread
2、复写Thread类中run方法//将自定义代码存放在run中让线程运行
3、调用线程start方法//开启线程并执行该线程的run方法
      该方法的两个作用:启动线程,调用run方法
   run方法仅仅是对象调用方法,而线程创建了并没有运行

发现每一次的运行结果都不同,为什么
因为多个线程都获取cpu的执行权。cpu执行到谁谁就执行
明确一点,在某一刻时,只能有一个程序在运行(多核除外)
cpu在做着高速的切换以达到看上去同时运行的效果。

为什么要覆盖run方法呢?
Thread类用于描述线程
该类就定义了一个功能,用于储备线程要运行的代码。该存储功能就是run方法
也就是说Thread类中的run方法,用于储存线程要运行的代码。

d.star();//开启线程,并执行该线程的run方法
d.run();//仅仅是对象调用方法,而线程创建了并没有运行

线程都有自己默认的名称
Thread-编号 //该编号从0开始

static Thread currentThread():获取当前线程对象
getName():获取线程名称
setName():设置线程名称

创建线程的第二种方式:实现Runnable接口(常用方式)
步骤:1、定义类实现Runnable接口
2、覆盖Runnable接口中的run方法//将线程要运行的代码存放在该run方法中
3、通过Thread类建立线程对象
4、将Runnable接口的子类对象作为实际参数传递给Thread类构造函数
5、调用Thread类的star方法开启线程并调用Runnable接口子类的run方法。

为什么要将Runnable接口的子类对象传递给Thread的构造函数?
因为自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程去指定,指定对象的run方法,就必须明确该方法所属对象。

实现方法和继承方法的不同:
实现方式的好处:避免了单继承的局限性,在定义线程时,建议使用实现方式。
继承Thread:线程代码存放在Thread子类run方法中
实现Runnable:线程代码存放在接口子类run方法中

三、线程的运行状态



四、多线程的安全问题
class Ticket implements Runnable//定义类,实现Runnable接口{private  int tick = 1000;public void run()//覆写run方法{while(true){if(tick>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);}}}}class  TicketDemo2{public static void main(String[] args) {Ticket t = new Ticket();//通过Thread建立线程对象Thread t1 = new Thread(t);//将Runnable接口的子类对象作为实参传递给Thread类构造函数Thread t2 = new Thread(t);Thread t3 = new Thread(t);Thread t4 = new Thread(t);t1.start();//调用star方法t2.start();t3.start();t4.start();}}

出现如下安全问题



问题的原因:
当多条语句当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
另一个线程参与进来执行。导致共享数据的错误。

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

Java对于多线程的安全问题提供了专业的解决方式。
就是同步代码块。
synchronized(对象)
{
需要被同步的代码
}


同步的前提:
1、必须要有两个或者两个以上的线程
2、必须要多个线程使用同一个锁
必须保证同步中只有一个锁在运行。
同步的好处:解决了多线程的安全问题。
同步的弊端:多个线程需要判断锁,较为消耗资源。

同步函数用的锁是this

如果同步函数被static修饰,这时的同步函数用的是什么锁?
静态进入内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
静态的同步方法使用的锁是该方法所在类的字节码文件对象。类名.class

五、多线程中的单例设计模式
考点问题:
Q:写一个延时加载的单例模式
A:懒汉式

Q:饿汉式和懒汉式的区别
A:懒汉式是一种延迟加载的方式

Q:当出现多线程访问时应该怎么解决
A:加同步解决安全问题

Q:效率高么
A:不高

Q:怎么解决?
A:通过双重判断的形式解决

懒汉式代码如下
class Single{private static Single s = null;private Single(){}public static  Single getInstance(){if(s==null){synchronized(Single.class)//锁是字节码文件对象{if(s==null)s = new Single();}}return s;}}

饿汉式没有安全问题,代码如下
class Single{private static final Single s = new Single();private Single(){}public static Single getInstance(){return s;}}

六、死锁
死锁就是同步中嵌套同步,而锁却不同。导致程序卡住不能继续执行。
代码示例:
class Test implements Runnable{private boolean flag;Test(boolean flag){this.flag = flag;}public void run(){if(flag){while(true){synchronized(MyLock.locka)//a锁{System.out.println("if locka");synchronized(MyLock.lockb)//b锁{System.out.println("if lockb");}}}}else{while(true){synchronized(MyLock.lockb)//b锁{System.out.println("else lockb");synchronized(MyLock.locka)//a锁{System.out.println("else locka");}}}}}}class MyLock//创建两个不同的锁{static Object locka=new Object();static Object lockb=new Object();}class  DeadLock{public static void main(String[] args) {//创建并启动两个进程Thread t1 = new Thread(new Test(true));Thread t2 = new Thread(new Test(false));t1.start(); t2.start();}}
运行结果:























0 0
原创粉丝点击