黑马程序员java学习—多线程1

来源:互联网 发布:java继承的定义 编辑:程序博客网 时间:2024/05/17 01:28

进程:正在进行中的程序。 

线程:就是进程中一个执行单元或执行情景或执行路径

  负责进程中程序执行的控制单元 。

一个进程中至少要有一个线程。 

当一个进程中线程有多个时,就是多线程。 

多线程解决的问题:可以让多部分代码同时执行。

什么是同时执行呢?其实都是cpu在瞬间做着快速切换完成的。

cpu的切换随机的,按照时间片的方式来完成。

java运行就是多线程的。

在执行main函数中内容的同时,垃圾回收器也在回收堆内存的垃圾。

所以执行main方法的线程,和执行垃圾回收器的线程同时在执行。

这就是多线程。

而且每一个线程都有自己要执行的内容,这个内容称之为:线程的任务。 

简单说:

启动线程就是为了执行任务,当任务有多个需要同时执行时,就需要多个线程。 

System.gc();//启动了垃圾回收器。垃圾回收器在回收每一个对象垃圾时,都会自动的调用该对象的finalize方法。

在java的lang包中,去找描述线程的类. Thread

通过查阅Thread类的描述,发现

创建线程有两种方式:

方式一:继承Thread类,覆盖run方法。

步骤:

1,定义类继承Thread类。

2,覆盖Thread类中的run方法。

3,创建Thread类的子类对象创建线程对象。

4,调用线程对象的start方法开启线程。

主线程要运行的任务都在main函数中。

自定义的线程要运行的任务都在run方法中。 

run方法就是专门用于存储线程任务代码的地方。

要运行线程,必须使用start方法。

start方法做了两件事:1,开启了线程让线程可以运行,2,调用了run方法。

调用run方法和调用start方法的区别:

调用run方法,仅仅是一般对象在调用对象中的方法,并没有开启线程,

还得主线程来完成run方法的运行。

调用start方法,是开启了一个线程(一个新的执行路径。)

这个线程去执行了run方法。

Thread类中的getname方法是返回线程名字。

Thread.currentThread():获取当前执行线程的对象 

Thread.currentThread().getName()获取当前执行线程的名字。

例如:main中 d1.run();

d2.run();

而d1=new Demo();

class Demo extends Thread{

public void run(){

System.out.println(Thread.currentThread().getName());结果是当前执行线程对象名main

System.out.println(this.getName());结果是当前的线程子类对象Demo的线程名Thread0

}

}

每个线程都有自己所属的栈区。

多线程的运行状态:

被创建:start()

运行状态:这种状态的线程具备着cpu的执行资格、执行权

消亡状态:stop()或run方法结束

冻结状态:这种状态的线程 ,释放了cpu的执行资格、执行权

临时阻塞状态:这种状态的线程具备着cpu的执行资格,不具备cpu的执行权

由运行状态到冻结状态:sleep(time)此方法time时间一到就可被执行或进入临时阻塞状态(就绪状态);第二种方法就是wait()方法,永久除非notify()唤醒。

创建线程方式二:

1,定义一个类实现Runnable接口。

2,覆盖Runnable接口中的run方法。

将线程要运行的代码存储到run方法中。 

3,创建该接口的子类对象。

4,通过Thread类进行线程的创建,并将Runnable接口的子类对象作为Thread类的构造函数的实参进行传递。

为什么要传递呢?

让线程对象创建时,就要明确要运行哪个run方法,而这个run方法是需要被对象调用的,

所以将run方法所属的对象传递给Thread类的构造函数。

5,调用Thread类中的start方法开启线程。 

Runnable接口的由来其实就是将线程的任务进行对象的封装。

将线程任务封装成对象后,通过Runnable接口可以降低和Thread对象的耦合性。

如果是继承Thread类,覆盖run方法这种情况,

Thread的子类即封装了线程的任务,而且自身还是一个线程对象。而实现Runnable接口的子类对象只是实现了run()方法,自身并不是一个线程对象。

这就是任务和对象耦合性过高。

Runable接口的出现,线程对象在使用该接口,

我们只要实现该接口即可。将实现的子类对象,也就是线程任务传递给线程对象就哦了。

以后创建线程建议使用第二种方式就是实现Runnable接口的方式。 

该方式避免单继承的局限性。 

线程安全问题:

安全问题产生的原因:

1,多个线程在操作共享数据。

2,操作共享数据的代码有多条。

一个线程在执行多条操作共享数据的过程中,其他线程参数与了运算,这时就会发生安全问题。

想要分析是否安全问题:

依据:线程任务中有没有共享数据,该数据是否被多条语句操作啊。

解决方案:只要保证一个线程在执行多条操作共享数据的语句时,其他线程不能参与运算即可。

当该线程都执行完后,其他线程才可以执行这些语句。

代码表现:java中给我们提供具体的解决语句。 

那就是同步代码块。

格式:

synchronized(对象)//对象可以是任意的对象。

{

需要被同步的语句。

}

同步的原理:其实就是将需要同步的代码进行封装,并在该代码上加了一个锁。

同步的好处:解决多线程的安全问题。

同步的弊端:会降低性能。 

同步的前提:

必须要保证在同步中有多个线程。因为同步中只有一个线程该同步是没有意义。

必须要保证多个线程在同步中使用的是同一个锁。

必须保证多个线程使用的锁是同一个。

这时才成为多个线程被同步了。