Java 程序设计 第八章 线程

简介: Java 程序设计 第八章 线程

第8章 线程

线程可以让一个程序同时执行多个任务,在实际程序应用地非常广泛。

8.1 理解线程

8.1.1进程的概念

了解线程前先了解一下进程,进程可以看成是程序的执行,可以把一个程序的执行过程看成是一个进程。

比如我们打开一个Word程序,就有一个Word程序进程。

8.1.2 线程的概念(此处是个人理解。)

一个进程可以有多个线程,同时执行多个任务。同样用Word举例,Word显示可以看成是一个线程,编辑可以看出是一个线程。

8.1.3 线程的生命周期

线程的生命周期有4种基本状态:

1.产生

2.中断

3.非中断(运行或可运行)

4.退出

8.2 线程类设计

8.2.1 线程API类图

Thread类是线程实现的主类,其核心过程方法由Runnable接口规范。

 

8.2.2  线程类Thread的构造方法

1.Thread(String threadName);  //创建指定名称的线程类

2.Thread();                              //线程类名称系统自动指定Thread-编号

3.Thread(Runnable target)  //target为目标对象,target需要实现Runnable接口,给出run()方法。

8.3 线程实现

线程的实现一般有两种方式:

(1)创建Thread类的子类,并重新定义run()方法,用户只要创建子类对象就能建立自己的线程。

(2)创建实现Runnable接口的类,并实现run()方法。

8.3.1 继承实现

方式一:继承Thread类

public class ThreadDemo extends Thread{
  public void run() {
    //线程代码实现
    System.out.println("线程执行");
  }
  public static void main(String[] args) {
    ThreadDemo th = new ThreadDemo();
    th.start();
  }
}

8.3.2接口实现

方式二:实现Runnable接口

 

public class ThreadDemo2{
  public static void main(String[] args) {
    Thread th  = new Thread(new MyThImpl());
    th.start();
  }
}
class MyThImpl implements Runnable{
  public void run() {
    //线程代码实现
    System.out.println("线程执行");
  }
}

8.4 线程控制

8.4.1 监控线程状态

线程状态在枚举类型Thread.State中定义。

NEW:新创建,还没调用start()

RUNNABLE:run()中代码被执行

BLOCKED:阻塞,等待解锁

WAITING:另一个线程运行,本线程等待

TIMED_WAIYING:等待到指定时间

TERMINATED:线程退出run()

获取线程状态方法:

public Thread.State getState()

 

8.4.2 线程休眠

Thread的sleep()方法

public class sleep1 {
  public static void main(String[] args) throws InterruptedException {
    for(int i=0;i<20;i++) {
      System.out.println("main"+i);
      Thread.sleep(1000);
    }
  }
}

注意:(1)sleep是静态方法,睡眠的是当前运行的线程、

 

8.4.3 中断线程

public void interrupt() :中断当前阻塞与等待状态,强制线程抛出异常。

 

8.4.4 阻塞进程 join()

void join(): 当前线程等待加入该线程后面,等待该线程终止

void join(long millis):当前线程等待该线程终止的时间最长为millis毫秒,如果超时还没执行完,当前线程也会进入就绪状态。

void join(long millis, int nanos);等待时间millis毫秒+nanos纳秒

8.4.5线程等待和唤醒

public final void wait() throws InterruptedException
public final void wait(long timeout,int nanos)throws InterruptedException
void notify()
void notifyAll()

如果线程等待用sleep(),唤醒用interrupt()

等待用join(),唤醒用interrupt()

等待用wait(),唤醒用notify();

 

8.4.6线程终止

当前线程放弃调度执行权力,等待下次排队执行。

public static void yield()

 

..线程控制综合实例

 

import java.util.Scanner;
public class sleep1 {
  private static int data = -1;
  private static Thread thread = new Thread(new Runnable() {
    public void run() {
      System.out.println("线程已经启动,输入0开始计数");
      for(int i=10;i>0;i--) {
        while(data != 0) {
          Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+":"+i);
        try {
          Thread.sleep(100);
        }catch(InterruptedException e) {
          e.printStackTrace();
        }
        
      }
    }
  });
  public static void main(String[] args) {
    thread.start();
    Scanner in = new Scanner(System.in);
    while(data == -1) {
      try {
        data=Integer.parseInt(in.nextLine());
        if(data!=0) {
          System.out.println("enter 0 to start counting");
          data = -1;
        }
      }catch(NumberFormatException e) {
        System.out.println("请输入整数");
      }
    }
  in.close(); 
  }
}
 
 
 

8.5 线程属性

8.5.1 优先级

优先级较高的线程获取CPU资源的概率较大。

每个线程默认的优先级和父线程相同。

Thread类提供setPriority(int newPriority和getPriority)和getPriority()方法来设置和得到优先级。

setPriority的参数时一个整数,范围1~10. (10最高)。

优先级实例:

 
public class priority1 {
  public static void main(String[] args) {
    new MyThread("低级",1).start();
    new MyThread("高级",10).start();
  }
}
class MyThread extends Thread{
  public MyThread(String name,int pro) {
    super(name);
    setPriority(pro);
  }
  public void run() {
    for(int i=0;i<=100;i++) {
      System.out.println(this.getName()+"线程第"+i+"次执行");
    }
  }
}

多次运行可以发现,多数情况下优先级高的先运行完成。

8.5.2 守护线程

Java中有两类线程:用户线程User Thread 和 守护线程Daemon Thread

守护线程具有最低优先级,为系统其它对象提供服务。

一般不会自己操作守护进程。

 

8.6线程同步

8.6.1Synchronized同步方法和同步代码块

保护某段代码只能同时被一个线程执行的技术成为线程同步。

关键字synchronized是Java内部实现的一个简单锁,可以用synchronized锁定一段代码:

public static void biz() {
    synchronized(Object.class) {
      a++;
      b++;
      if(a!=b) {
        System.out.println(a+"!="+b);
      }
    }
  }

或者锁定整个方法:

  synchronized public static void biz() {
      a++;
      b++;
      if(a!=b) {
        System.out.println(a+"!="+b);
      }
    
  }

8.6.2 同步变量volatile关键字

Java变量前可以加修饰语volatile,volatile的主要目的是解决成员变量的多线程访问同步问题。

在读取加了volatie修饰的变量时,会直接从内存读取。

但volatile不保证对变量的操作是原子操作。

Java提供java.util.concurrent.automic包,提供了基本类型与引用类型的原子性操作封装类:

AtomicBoolean

AtomicInteger

AtomicIntegerArray

...

 

8.6.3线程锁Lock接口及ReentrantLock类

8.6.4 死锁

不同线程都在等待那些不可能被释放的锁时,就成了死锁。

构成死锁的典型是锁交叉。


相关文章
|
1天前
|
Java
死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`
【6月更文挑战第20天】死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`volatile`保证变量的可见性和部分原子性,确保多线程环境中值的即时更新。与`synchronized`相比,`volatile`作用于单个变量,不保证原子操作,同步范围有限,但开销较小。`synchronized`提供更全面的内存语义,保证原子性和可见性,适用于复杂并发控制。
11 3
|
1天前
|
Java
【技术瑜伽师】Java 线程:修炼生命周期的平衡之道,达到多线程编程的最高境界!
【6月更文挑战第19天】Java多线程编程犹如瑜伽修行,从创建线程开始,如`new Thread(Runnable)`,到启动线程的活跃,用`start()`赋予生命。面对竞争与冲突,借助同步机制保证资源访问的有序,如`synchronized`关键字。线程可能阻塞等待,如同瑜伽的静止与耐心。完成任务后线程终止,整个过程需密切关注状态变换,以求多线程间的和谐与平衡。持续修炼,如同瑜伽般持之以恒,实现高效稳定的多线程程序。
|
1天前
|
Java
【代码诗人】Java线程的生与死:一首关于生命周期的赞歌!
【6月更文挑战第19天】Java线程生命周期,如诗般描绘了从新建到死亡的旅程:创建后待命,`start()`使其就绪,获得CPU则运行,等待资源则阻塞,任务完或中断即死亡。理解生命周期,善用锁、线程池,优雅处理异常,确保程序高效稳定。线程管理,既是艺术,也是技术。
|
1天前
|
安全 Java
【极客档案】Java 线程:解锁生命周期的秘密,成为多线程世界的主宰者!
【6月更文挑战第19天】Java多线程编程中,掌握线程生命周期是关键。创建线程可通过继承`Thread`或实现`Runnable`,调用`start()`使线程进入就绪状态。利用`synchronized`保证线程安全,处理阻塞状态,注意资源管理,如使用线程池优化。通过实践与总结,成为多线程编程的专家。
|
1天前
|
Java 开发者
JAVA多线程初学者必看:为何选择继承Thread还是Runnable,这其中有何玄机?
【6月更文挑战第19天】在Java中创建线程,可选择继承Thread类或实现Runnable接口。继承Thread直接运行,但限制了多重继承;实现Runnable更灵活,允许多线程共享资源且利于代码组织。推荐实现Runnable接口,以保持类的继承灵活性和更好的资源管理。
|
1天前
|
Java 开发者
告别单线程时代!Java 多线程入门:选继承 Thread 还是 Runnable?
【6月更文挑战第19天】在Java中,面对多任务需求时,开发者可以选择继承`Thread`或实现`Runnable`接口来创建线程。`Thread`继承直接但限制了单继承,而`Runnable`接口提供多实现的灵活性和资源共享。多线程能提升CPU利用率,适用于并发处理和提高响应速度,如在网络服务器中并发处理请求,增强程序性能。不论是选择哪种方式,都是迈向高效编程的重要一步。
|
1天前
|
Java 开发者
震惊!Java多线程的惊天秘密:你真的会创建线程吗?
【6月更文挑战第19天】Java多线程创建有两种主要方式:继承Thread类和实现Runnable接口。继承Thread限制了多重继承,适合简单场景;实现Runnable接口更灵活,可与其它继承结合,是更常见选择。了解其差异对于高效、健壮的多线程编程至关重要。
|
2天前
|
Java 开发者
【技术成长日记】Java 线程的自我修养:从新手到大师的生命周期修炼手册!
【6月更文挑战第19天】Java线程之旅,从新手到大师的进阶之路:始于创建线程的懵懂,理解就绪与运行状态的成长,克服同步难题的进阶,至洞悉生命周期的精通。通过实例,展示线程的创建、运行与同步,展现技能的不断提升与升华。
|
2天前
|
Java
【代码诗人】Java线程的生与死:一首关于生命周期的赞歌!
【6月更文挑战第19天】在Java中,线程经历新建、就绪、运行、阻塞和死亡5个阶段。通过`start()`从新建转为就绪,进而可能运行;阻塞可能因等待资源;完成任务或中断后死亡。管理线程生命周期涉及合理使用锁、线程池、异常处理和优雅关闭,如使用`volatile`和中断标志。了解这些,能提升程序效率和稳定性。
|
1天前
|
Java
JAVA多线程深度解析:线程的创建之路,你准备好了吗?
【6月更文挑战第19天】Java多线程编程提升效率,通过继承Thread或实现Runnable接口创建线程。Thread类直接继承启动简单,但限制多继承;Runnable接口实现更灵活,允许类继承其他类。示例代码展示了两种创建线程的方法。面对挑战,掌握多线程,让程序高效运行。