第九章~线程

1.线程的基本概念
(1)线程是一个程序内部的顺序控制流。
(2)线程和进程的区别:
(a)每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。
(b)进程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。
(c)多进程:在操作系统中能同时运行多个任务(程序)。
(d)多线程:在同一个应用程序中有多个顺序流同时执行。
(3)Java的线程是通过java.lang.Thread类来实现的。
(4)VM启动时会有一个由主方法(public static void main(){})所定义的线程。
(5)可以通过创建Thread的实例来创建新的线程。
(6)每个线程都是通过某个特定Thread对象所相应的方法run()来完成其操作的,方法run()称为线程体。
(7)通过调用Thread类的start()方法来启动一个线程。

2.线程的创建和启动
(1)可以有两种方式创建新的线程:
第一种:
(a)定义线程类实现Runnable接口
(b)Thread myThread = new Thread(target)//target为Runnable接口类型。
(c)Runnable中只有一个方法:
public void run();//用以定义线程运行体。
(d)使用Runnable接口可以为多个线程提供共享数据。
(e)在实现Runnable接口的类的run方法定义中可以使用thread的静态方法:
public static Thread currentThread() 获取当前线程的引用。
第二种:
(a)可以定义一个Thread的子类并重写其run方法如:
class MyThread extends Thead{
public void run(){…}
}
(b)然后生成该类的对象:
MyThread myThread = new MyThread(…);

例子:

public class TestThread1 {

 public static void main(String[] args) {
  Runner1 r = new Runner1();
  //方法调用
//  r.run();

  //线程启动1
//  Thread t = new Thread(r);
//  t.start();

//线程启动2
  r.start();

  for(int i=0;i<100;i++) {
   System.out.println("Main Thread:------" + i);
  }
 }
}

//线程启动1---接口
//class Runner1 implements Runnable{
// public void run() {
//  for(int i=0;i<100;i++) {
//   System.out.println("Runner1 :" + i);
//  }
// }
//}

//线程启动2---继承
class Runner1 extends Thread{
 public void run() {
  for(int i=0;i<100;i++) {
   System.out.println("Runner1 :" + i);
  }
 }
}

注意:
两种线程启动方法,优先选择实现接口启动线程方法,因为接口比较灵活。

3.线程的调度和优先级
(1)Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定应调度哪个线程来执行。
(2)线程的优先级用数字表示,范围从1到10,一个线程的缺省优先级是5。
(a) Thread.MIN_PRIORITY = 1
(b) THread.MAX_PRIORITY = 10
(c) Thread.NORM_PRIORITY = 5
(3)使用下述线程方法获得或设置线程的对象的优先级:
(a) int getPriority();
(b) void setPriority(int newPriority);

例子:

public class TestPriority {

 public static void main(String[] args) {
  Thread t1 = new Thread(new T1());
  Thread t2 = new Thread(new T2());
  t1.setPriority(Thread.NORM_PRIORITY + 3);//把t1的优先级提高3
  t1.start();
  t2.start();
 }
 
}

class T1 implements Runnable{
 public void run() {
  for(int i=0;i<1000;i++) {
   System.out.println("T1: " + i);
  }
 }
}


class T2 implements Runnable{
 public void run() {
  for(int i=0;i<1000;i++) {
   System.out.println("------T2: " + i);
  }
 }
}

4.线程的状态控制
(1)线程状态转换
创建—>start()—>就绪状态<–调度–>运行状态—>结束
运行状态—导致阻塞的事件—>阻塞状态—阻塞解除—>就绪状态

(2)基本方法:
isAlive 判断线程是否还“活着”,即线程在启动后还未终止
getPriority() 获得线程的优先级数值
setPriority() 设置线程的优先级数值
Thread.sleep 将当前线程睡眠指定毫秒数
join 调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,再恢复当前线程的运行。
yield() 让出CPU,当前线程进入就绪队列等待调度
wait() 当前线程进入对象的wait pool
notify/notifyAll() 唤醒对象的wait pool中的一个/所有等待线程
(3)sleep方法
(a)可以调用Thread的静态方法:
public static void sleep(long millis) throws InterruptedException
使得当前线程休眠(暂时停止执行millis毫秒)。
(b)由于是静态方法,sellp可以由类名直接调用:Thread.sleep(…)

例子:

import java.util.*;
public class TestInterrupt {

 public static void main(String[] args) {
  MyThread thread = new MyThread();
  thread.start();
  try{
   Thread.sleep(10000);
  }catch(InterruptedException e) {
   thread.interrupted();
  }
 }
 
}

class MyThread extends Thread{
 boolean flag = true;
 public void run() {
  while(flag) {
   System.out.println("===" + new Date() + "===");
   try {
    sleep(1000);
   }catch(InterruptedException e) {
    return;
   }
  }
 }
}

注:在那个线程里调用sleep方法,就那个线程睡眠。

(4)join方法
合并某个线程

例子:


public class TestJoin {

 public static void main(String[] args) {
  MyThread2 t1 = new MyThread2("t1");
  t1.start();
  try {
   t1.join();
  }catch(InterruptedException e) {}
  for(int i=0;i<=10;i++) {
   System.out.println("i am main thread");
  }
 }

}

class MyThread2 extends Thread{
 MyThread2(String s){
  super(s);
 }
 public void run() {
  for(int i=1;i<=10;i++) {
   System.out.println("i am " + getName());
   try {
    sleep(1000);
   }catch(InterruptedException e) {
    return;
   }
  }
 }
}

(5)yield方法
让出CPU,给其他线程执行的机会

例子:

public class TestYield {

 public static void main(String[] args) {
  MyThread3 t1 = new MyThread3("t1");
  MyThread3 t2 = new MyThread3("t2");
  t1.start();
  t2.start();
 }
 
}

class MyThread3 extends Thread{
 MyThread3(String s){
  super(s);
 }
 public void run() {
  for(int i=0;i<=100;i++) {
   System.out.println(getName() + ": " + i);
   //每当i可以整除10的时候,则让出CUP位置给其他线程执行
   if(i%10==0) {
    yield();
   }
  }
 }
}

5.线程同步
(1)在Java语言中,引入了对象互斥锁的概念,保证共享数据操作的完整性。每个对象都对应于一个可称为“互斥锁”的标记,这个标记保证在任一时刻,只能有一个线程访问该对象。
(2)锁定机制,在执行当前方法的过程中当前方法被锁定
synchronized(this){…}

public synchronized void add(String name){…}

6.补充
(1)同一个线程类可以启动两个线程

public class TestThread2 {

 public static void main(String[] args) {
  Runner2 r = new Runner2();
  Thread t1 = new Thread(r);
  Thread t2 = new Thread(r);
  t1.start();
  t2.start();
 }

}

class Runner2 implements Runnable{
 public void run() {
  for(int i=0;i<10;i++) {
   System.out.println(i);
  }
 }
}

(2)线程的中断结束方法

public class TestThread4 {

 public static void main(String[] args) {
  Runner4 r = new Runner4();
  Thread t = new Thread(r);
  t.start();
  for(int i=0;i<100;i++) {
   if(i%10==0) {
    System.out.println("in thread main i= " + i);
   }
  }
  System.out.println("Thread main is over");
  r.shutDown();
  //t.stop();//不要用该方法
 }

}

class Runner4 implements Runnable{
 private boolean flag = true;
 
 public void run() {
  int i=0;
  while(flag==true) {
   System.out.println(" " + i++);
  }
 }
 public void shutDown() {
  flag = false;
 }
}

(3)isAlive 方法

public class TestThread6 {

 public static void main(String[] args) {
  Thread t = new Runner6();
  t.start();
  for(int i=0;i<50;i++) {
   System.out.println("MainThread: " + i);
  }
 }

}

class Runner6 extends Thread{
 public void run() {
  //currentThread拿到当前线程;isAlive判断线程是否“活着”,“活着”则true
  System.out.println(Thread.currentThread().isAlive());
  for(int i=0;i<50;i++) {
   System.out.println("SubThread: " + i);
  }
 }
}

(4)wait和sleep之间的区别:
(a)wait 时,别的线程可以访问锁定对象。调用wait方法的时候必须锁定该对象。
(b)sleep 时,别的线程不可以访问锁定对象。

猜你喜欢

转载自blog.csdn.net/Zhou2016127224/article/details/84105482