Java3 多线程
资料来源:《Java程序设计基础(第六版)》
Java支持多线程,使各代码段并发执行。
Q:并发和并行的区别
A:并行是指同一时刻有多个代码在处理器上执行,需硬件支持;并发执行是在单处理器上,同一时刻只能执行一个代码,但同一时段内代码段交替执行,实现“微观串行,宏观并行”。
基本概念:
程序(program):静态的代码
进程(process):一个运行中的程序。进程是操作系统资源分配和处理器调度的基本单元。
线程(thread):包含在进程内,同类的多个线程共享内存空间和系统资源
线程的5种状态:
- newborn:已经分配资源,未调度
- runnable:可运行,进入线程队列等待CPU资源
- running:线程对象拥有CPU控制权后调用run()方法
正在运行的线程将在以下情况退出:
1.线程执行完毕
2.有优先级更高的线程处于runnable状态
3.线程主动睡眠
4.线程等待某一资源 - blocked:因某种原因不能执行线程
1.调用sleep() / yield()方法
2.为等待条件变量,调用wait()方法
3.与另一线程join() - dead:正常执行完后/进程停止运行时,线程变为dead状态
线程的调度
- 分时模型:CPU资源按时间片分配,时间片使用完毕必须让出
- 抢占模型:高优先级先执行
创建线程
- Thread的子类
- Runnable接口(解决多重继承的问题 ,有利于数据共享),注意实现了Runnable接口的类并不具有线程的支持,还必须使用Thread(Runnable target)创建线程对象
package src;
class MyThread implements Runnable{
public void run() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep((int)(1000 * Math.random()));
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + " is running");
}
}
}
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
t1.start();
t2.start();
System.out.println("Main Thread");
}
}
Output:
Main Thread
Thread-0 is running
Thread-0 is running
Thread-1 is running
Thread-0 is running
Thread-1 is running
Thread-1 is running
join()方法
调用此方法的线程立即执行,正在执行的线程转为Runnable状态,且需要等到之前的线程执行完。
// 修改之前的main方法
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
System.out.println(t1.getName() + "interrupted");
}
t2.start();
System.out.println("Main Thread");
}
Output:
Thread-0 is running
Thread-0 is running
Thread-0 is running
Main Thread
Thread-1 is running
Thread-1 is running
Thread-1 is running
线程间通信
wait():线程A执行了对象x的wait()方法,该线程暂停,进入x的等待队列,并释放x的互斥锁
notify():唤醒等待该对象互斥锁的第一个线程
notifyAll():唤醒等待该对象互斥锁的所有线程
一个线程基于对象x调用以上方法,该线程一定已经获得对象x的互斥锁,所以以上方法只能在sychronized代码块中调用
wait()和sleep()不同的地方是它暂时让出资源的控制权
例子:模拟一个存售票系统,必须满足售出一张后才能存入下一张
package src;
public class TicketSell {
public static void main(String[] args) {
Tickets t = new Tickets(10);
new Producer(t).start();
new Consumer(t).start();
}
}
class Tickets {
int size;
int num = 0;
boolean available = false;
public Tickets(int size) {
this.size = size;
}
public synchronized void put() {
if (available) {// need to sell first
try {
wait();
} catch (Exception e) {
}
}
System.out.println("Store ticket " + num);
available = true;
notify();
}
public synchronized void sell() {
if (!available) {// need to put first
try {
wait();
} catch (Exception e) {
}
}
System.out.println("Sell ticket " + num++);
available = false;
notify();
}
}
class Producer extends Thread {
Tickets t;
public Producer(Tickets t) {
this.t = t;
}
public void run() {
while (t.num < t.size) {
t.put();
}
}
}
class Consumer extends Thread {
Tickets t;
public Consumer(Tickets t) {
this.t = t;
}
public void run() {
while (t.num <= t.size) {
t.sell();
}
}
}
Output:
Store ticket 0
Sell ticket 0
Store ticket 1
Sell ticket 1
Store ticket 2
Sell ticket 2
Store ticket 3
Sell ticket 3
Store ticket 4
Sell ticket 4
Store ticket 5
Sell ticket 5
Store ticket 6
Sell ticket 6
Store ticket 7
Sell ticket 7
Store ticket 8
Sell ticket 8
Store ticket 9
Sell ticket 9
Store ticket 10
Sell ticket 10
Process finished with exit code 0