Java 程序设计 第 8 章 多线程
第 8 章 Java 的多线程 8.1 线程及其创建 Java 中的线程 Java 程序通过流控制来执行程序流,程序中单个顺序的流 控制称为线程, 多线程则指的是在单个程序中可以同时运行 多个不同的线程执行不同的任务。 单个程序内部也可以在同一时刻进行多种运算。 很多程序语言需要利用外部的线程软件包来实现多线程, 而 Java 则内在支持多线程,它的所有类都是在多线程的思 想下定义的。
第 8 章 Java 的多线程 线程 线程就是程序中单独顺序的流控制。 Java 的线程是通过 Java 的软件包 java.lang 中定 义的类 Thread 来实现的。
第 8 章 Java 的多线程 线程体 线程的所有活动都是通过线程体 ---- run() 方法来实现的。 在一个线程被建立并初始化以后, Java 的运行时系统就自 动调用 run() 方法。 正是通过 run() 方法才使得建立线程的目的得以实现。 通常, run() 方法是一个循环,例如一个播放动画的线程 要循环显示一系列图片。 有时, run() 方法会执行一个时间较长的操作,例如下载 并播放一个 JPEG 格式的电影。
第 8 章 Java 的多线程 创建线程对象的两种方法 1 .通过继承 Thread 类创建线程 class MyThread extends Thread { public void run() { for(int i=0;i<100;i++) { System.out.print (" " + i); } } 2 .通过向 Thread() 构造方法传递 Runnable 对象来创建线程 class MyTask implements Runnable { public void run() { … } } Thread thread = new Thread(mytask); thread.start(); 3. 可用匿名类来实现 Runnable ,如 TestThread4Anonymous.java
第 8 章 Java 的多线程 多线程 TestThread3.java 多线程。 ThreadDraw.java 多线程绘图。
第 8 章 Java 的多线程 8.2 线程的控制
第 8 章 Java 的多线程 线程的状态与生命周期 在一个线程的生命周期中,它总处于某一种状态 中。 线程的状态表示了线程正在进行的活动以及在这 段时间内线程能完成的任务。
第 8 章 Java 的多线程 线程优先级 Thread 类有三个有关线程优先级的静态常量: MIN_PRIORITY , MAX_PRIORITY , NORM_PRIORITY
第 8 章 Java 的多线程 对线程的基本控制 结束线程 现在一般采取给线程设定一个标记变量的方法来决定线 程是否应该终止。 设定线程的优先级 可以使用 Thread 对象的 setPriority( int priority) 方法
第 8 章 Java 的多线程 线程 的启动: start() 暂时阻止线程的执行 Thread.sleep(long millisecond ) 来挂起线程的执行 try{ Thread.sleep( 1000 ); } catch( InterruptedException e ){ // …. } join() 方法。调用某 Thread 对象的 join() 方法,可以将一个线程加入到本 线程中,本线程的执行会等待另一线程执行完毕。 Thread t; // t 是另一线程 try{ t.join(); } catch( InterruptedException e ){ // …. }
第 8 章 Java 的多线程 后台线程 线程有两种,一类是 Daemon 线程,一类是非 Daemon 线程。在 Java 程序中,若还有非 Demon 线程,则整个程序就不会结束;当正在运行的线 程都是守护线程时, Java 虚拟机退出。 使用 setDaemon(true); 垃圾回收是后台线程 示例: TestThreadDaemon.java
第 8 章 Java 的多线程 8.3 线程的同步
第 8 章 Java 的多线程 多线程同步 线程都是独立的,而且异步执行,也就是说每个 线程都包含了运行时所需要的数据或方法,而不 需要外部的资源或方法,也不必关心其它线程的 状态或行为。但是经常有一些同时运行的线程需 要共享数据,例如一个线程向文件写数据,而同 时另一个线程从同一文件中读取数据,因此就必 须考虑其它线程的状态与行为,这时就需要实现 同步来得到预期结果。 示例: SyncCounter1.java
第 8 章 Java 的多线程 在 Java 语言中,引入了对象互斥锁的概念,来保证共 享数据操作的完整性。 每个对象都对应于一个可称为 “ 互斥锁 ” 的标记,这 个标记用来保证在任一时刻,只能有一个线程访问 该对象。 关键字 synchronized 用来与对象的互斥锁联系。 当某个对象用 synchronized 修饰时,表明该对象在 任一时刻只能由一个线程访问。 使用 wait() 方法可以释放对象锁 使用 notify() 或 notifyAll() 可以让等待的一个或所 有线程进入就绪状态
第 8 章 Java 的多线程 synchronized 除了象上面讲的放在对象前面限 制一段代码的执行外,还可以放在方法声明中, 表示整个方法为同步方法。 public synchronized void push(char c){ … } 如果 synchronized 用在类声明中,则表明该类中 的所有方法都是 synchronized 的。 示例: SyncCounter2.java
第 8 章 Java 的多线程 生产者 - 消费者问题 示例: ProducerConsumerStack.java class CubbyHole { private int index = 0; private int []data = new int[3]; public synchronized void put(int value){ while(index == data.length){ try{ this.wait(); }catch(InterruptedException e){} } data[index] = value; index++; this.notify(); }
第 8 章 Java 的多线程 public synchronized int get(){ while(index <=0){ try{ this.wait(); }catch(InterruptedException e){} } index--; int val = data[index]; this.notify(); return val; } }
第 8 章 Java 的多线程 8.4 并行 API java.util.concurrent 包 Lock 、 ReentrantLock lock() tryLock() unlock() 例: NoDeadLockDemo.java ReadWriteLock 、 ReentrantReadWriteLock.writeLock().lock(),.readLock().unlock() 例: ArrayList2.java
第 8 章 Java 的多线程 并行的集合类 产生一个线程安全的集合对象 Collections.synchronizedArrayList(list) CopyOnWriteArrayList 、 CopyOnWriteArraySet 适合于很少写入而迭代频繁的对象 ArrayBlockingQueue 生产者与消费者,使用 put() 及 take() ConcurrentHashMap putIfAbsent(), remove(), replace()
第 8 章 Java 的多线程 线程相关的其他问题 使用 java.util.Timer /TimerTask 类 示例 TimerTest.java 在线程中更新图形化界面,要调用 invokeLater 示例 ThreadDrawJ.java