Java之多线程

2019-03-02

java多线程学习一  基础

基础知识

进程  

一个进程就是一个执行中程序,而每一个进程都有自己独立的一块内存空间、一组系统资源。在进程的概念中,每一个进程的内部数据和状态都是完全独立的。

线程  

线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序控制的流程,但与进程不同的是:

同类滴多个线程是 共享一块内存空间和一组系统资源。 所以系统在各个线程之间切换时,开销要比进程小得多。所以线程好似 轻量级的进程。一个进程可以包含多个线程。

主线程  

Java程序至少会有一个线程,这就是主线程,程序启动后是由 JVM创建主线程,程序结束是由JVM停止主线程。 主线程负责管理 子线程,即子线程的 启动、挂起、停止等等操作。

获取主线程 lang包内类

Thread mainThread = Thread.currentThread();

 

 

//打印线程名

System.out.println(mainThread.getName());

 

 

创建子线程

创建一个子线程涉及到 java.lang.Thread类 和 java.lang.Runnable接口。

Thread是线程类,创建一个Thread对象 就会产生一个 新的 线程。

而线程执行的程序代码是在 实现Runnable接口对象 的run() 方法中编写的,实现Runnable接口的 对象 是线程执行对象。

继承 Thread类创建线程

 

 

public class ThreadTest extends Thread{ 

 public void run(){ 

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

 System.out.println("第"+i+"次 in "+Thread.currentThread().getName()); 

 } 

 System.out.println(Thread.currentThread().getName()+" 执行完毕!");

}

}

public class TestThread { 

public static void main(String[] args){ 

ThreadTest a=new ThreadTest(); 

a.setName("Tyrell");

a.start(); 

 new ThreadTest().start(); 

 new ThreadTest().start(); 

 }

}

 

 

      一旦线程启动后start方法就会立即返回,而不会等待到run方法执行完毕才返回。就好像run方法是在另外一个cpu上执行一样。  

主线程由Java虚拟机负责,程序员负责启动自己的 线程。使线程 执行 需要调用Thread类中的 start()方法,start()方法 调用 被 覆盖的run()方法,完成线程功能的真正代码,放在类 的run()方法中,当一个类继承Thread类后,就可以在类中覆盖run()方法。然后 主方法中调用 start()方法,执行线程,也就是调用run()方法。如果不调用start()方法,线程永远也不会启动。 在主方法没有调用 start() 方法前,Thread对象只是一个实例,而不是一个真正的线程。

实现Runnable接口  

如果需要继承其他类,那么就没有办法 通过继承Thread类 来使 当前类实现多线程了。Java不支持多继承,所以选择实现 Runnable接口。

`public class TTest extends Object implements Runnable`  

实质上 Thread类 实现了 Runnable接口 ,其中的run()方法 也正是对 Runnable接口 中run()方法的具体实现。实现Runnable接口的程序 会创建一个 Thread对象,并将Runnable对象 和 Thread对象相关联。Thread类中由两个构造方法:

```public Thread(Runnable target)public Thread(Runnable target,String name)```  

这儿还可以用匿名内部类 传入实现Runnable接口的匿名类,如:

 

 

Thread t=new Thread(new Runnable(){ 

 public void run(){

 // 

 },"myThread");

//可以省略线程名 myThreadt.start();

 

## 线程的生命周期

线程具有生命周期,其中包含7种状态,分别是

  出生状态:线程被创建时处于的状态,在用户使用该线程实例 调用 start()方法前,都处于出生状态。

  就绪状态:用户调用start()方法 后,线程处于就绪状态。

  运行状态:当线程得到系统资源后, 就进入运行状态。

  等待状态:当处于 运行状态的线程 调用 Thread类的wait()方法时,该线程进入等待状态。必须调用Thread类中的notify()方法 唤醒。notifyAll()方法是将所有处于等待状态的线程唤醒。

  休眠状态

  阻塞状态

  死亡状态

操作线程的方法

线程的休眠

线程休眠有可能抛出 InterruptedException(打扰,插嘴),所以sleep方法的调用要放到try{}catch(){} 块中。  虽然使用了 sleep()方法的线程在一段时间后 会醒来,但是并不能保证醒来后进入 运行状态,只能保证它进入就绪状态。```public void run(){ // Thread.sleep(999);//单位毫秒 秒/1000}```

### 线程的加入  如果当前程序为 多线程 程序。加入已经存在一个线程A,现在需要插入线程B。当某个线程 加入到零一个线程时,令一个线程会等待 该线程结束后 在继续执行。```//join():加入运行class Test implements Runnable{ public void run(){ for(int i=1;i<=10;i++){ System.out.println(Thread.currentThread().getName()+"--->"+i); } }}class Demo{ public static void main(String[] args) throws InterruptedException{ Test test = new Test(); Thread t1 = new Thread(test); Thread t2 = new Thread(test); t1.start();//t1 start之后不一定能抢到CPU //写在这里,加入下面这句话之后,这时只有主线程和t1线程,所以主线程会等待t1线程全部执行完再执行 //t1.join();//让t1线程加入线程,如果没有这句话,t1线程不一定能得到CPU t2.start(); t1.join();//写在这里,这时有主线程和t1,t2线程,主线程会等待t1线程执行完,t2线程不会让着t1 //join只有主线程会让着他 for(int i=1;i<=10;i++){ System.out.println(Thread.currentThread().getName()+"--->"+i); } }}```

### 线程的中断

### 线程的礼让  Thread类中提供了一种礼让方法,使用yield()方法表示。[e屈服,让步],它只是给当前正处于运行状态的线程一个提醒,告知它可以将资源礼让给其它线程,这仅仅时一种暗示,没有机制保证一定会礼让;  yield()方法使具有相同优先级的线程 有进入 可执行状态 的机会,当 当前线程放弃执行权时会再度回到就绪状态。对于支持多任务的操作系统来说,不需要调用yield()方法,操作系统会为线程自动分配CPU时间片 来执行。

## 线程的优先级线程的优先级 可以表明在 程序中 该线程的重要性,系统根据优先级决定运行那个线程。

可以用`thread.setProperty(优先级)方法调整``优先级 为 1--10默认优先级为 5`

## 线程同步 | 线程安全 线程同步机制

#### 同步块```public class Runner implements Runnable{ int num=10; int i=15; @Override public void run(){ while(i>0){ synchronized(""){ if(num>0){ try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("tickets "+num+" in"+Thread.currentThread().getName()); num--; } } i--; } } public static void main(String[] args){ Runner r = new Runner(); Thread t1=new Thread(r,"A"); Thread t2=new Thread(r,"B"); Thread t3=new Thread(r,"C"); t1.start(); t2.start(); t3.start(); }}```  将资源放置在 同步块中。这个同步块也称为临界区,它使用 synchronized 关键字建立。```synchronized(Object){//}```  通常将 共享资源 的操作放置在 synchronized 定义的区域内,这样当其他线程也获取到这个锁 时,必须等待 锁 被释放时 才能进入 该区域。----------

#### 同步方法```synchronized void function(){ //}```