细粒度
线程之间有同步协作
- 等待
- 通知/唤醒
- 终止
线程状态
- NEW 刚创建(new)
- RUNNABLE 就绪态(start)
- RUNNING 运行中(run)
- BLOCK 阻塞(sleep)
- TERMINATED 结束(terminated)
Thread的部分API已经废弃
- 暂停和恢复suspend/resume
- 消亡stop/destroy
线程阻塞/和唤醒
- sleep,时间一到,自己会醒来
- wait/notify/notifyAll,等待,需要别人来唤醒
- join,等待另一个线程结束
- interrupt,向另外一个线程发送中断信号,该线程接收到信息,会触发InterruptedException(可解除阻塞),并进行下一步处理
生产者消费者经典例子
消费者
package com.lihuan.thread.demo04;
public class Consumer implements Runnable{
private Storage storage;
public Consumer(Storage storage) {
this.storage = storage;
}
@Override
public void run() {
int i = 0;
while (i < 10){
i++;
storage.pop();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
生产者
package com.lihuan.thread.demo04;
import java.util.Random;
public class Producer implements Runnable{
private Storage storage;
public Producer(Storage storage){
this.storage = storage;
}
@Override
public void run() {
int i = 0;
Random r = new Random();
while (i < 10) {
i++;
Product product = new Product(i, "电话" + r.nextInt(100));
storage.push(product);
}
}
}
产品
package com.lihuan.thread.demo04;
public class Product {
private int id;
private String name;
public Product() {
}
public Product(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
仓库
package com.lihuan.thread.demo04;
public class Storage {
//厂库容量为10
private Product[] products = new Product[10];
private int top = 0;
public synchronized void push(Product product){
while (top == products.length){
try {
System.out.println("producer wait");
wait();//厂库满了,等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//把产品放入仓库
products[top++] = product;
System.out.println(Thread.currentThread().getName() + " 生产了产品" + product);
System.out.println("producer notifyAll");
notifyAll();//唤醒等待线程
}
public synchronized Product pop() {
while (top == 0) {
try {
System.out.println("consumer wait");
wait();//仓库空,等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//把产品拿出仓库
--top;
Product p = new Product(products[top].getId(), products[top].getName());
products[top] = null;
System.out.println(Thread.currentThread().getName() + " 消费了产品" + p);
System.out.println("consumer notifyAll");
notifyAll();//唤醒等待线程
return p;
}
}
主类
package com.lihuan.thread.demo04;
/**
* 经典生产者和消费者问题
*/
public class ProductTest {
public static void main(String[] args) {
Storage storage = new Storage();
Thread consumer1 = new Thread(new Consumer(storage));
consumer1.setName("消费者1");
Thread consumer2 = new Thread(new Consumer(storage));
consumer2.setName("消费者2");
Thread producer1 = new Thread(new Producer(storage));
producer1.setName("生产者1");
Thread producer2 = new Thread(new Producer(storage));
producer2.setName("生产者2");
producer1.start();
producer2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
consumer1.start();
consumer2.start();
}
}
线程被动地暂停和终止
- 依靠别的线程来拯救自己
- 没有及时释放资源
线程主动暂停和终止
- 定期监测共享变量
- 如果需要暂停或者终止,先释放资源,再主动动作
- 暂停:Thread.sleep(),休眠
- 终止:run方法结束,线程终止
例子:
package com.lihuan.thread.demo04.interrupt;
public class InterruptTest {
public static void main(String[] args) {
TestThread1 t1 = new TestThread1();
TestThread2 t2 = new TestThread2();
t1.start();
t2.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.interrupt();
t2.flag = false;
System.out.println("main thread is exiting");
}
}
//被动
class TestThread1 extends Thread{
@Override
public void run() {
while (!interrupted()){
System.out.println("test thread1 is running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
System.out.println("test Thread1 is exiting");
}
}
//主动
class TestThread2 extends Thread{
public volatile boolean flag = true;
@Override
public void run() {
while (flag){
System.out.println("test thread2 is running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("test thread2 is exiting");
}
}
多线程死锁
- 每个线程互相持有别人需要的锁(哲学家吃面问题)
- 预防死锁,对资源进行等级排序
package com.lihuan.thread.demo04.deadlock;
import java.util.concurrent.TimeUnit;
public class ThreadDemo5 {
public static Integer r1 = 1;
public static Integer r2 = 2;
public static void main(String[] args) {
TestThread51 t1 = new TestThread51();
t1.start();
TestThread52 t2 = new TestThread52();
t2.start();
}
}
class TestThread51 extends Thread{
@Override
public void run() {
synchronized (ThreadDemo5.r1){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (ThreadDemo5.r2){
System.out.println("TestThread51 is running");
}
}
}
}
class TestThread52 extends Thread{
@Override
public void run() {
synchronized (ThreadDemo5.r2){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (ThreadDemo5.r1){
System.out.println("TestThread52 is running");
}
}
}
}
可以使用 jvisualvm (命令:线程查看工具)进行死锁的查看
守护(后台)进程
- 普通线程的结束,是run方法运行结束
- 守护线程的结束,是run方法运行结束,或main函数结束
- 守护线程永远不要访问资源,如文件和数据库
package com.lihuan.thread.demo04.daemon;
public class ThreadDemo4 {
public static void main(String[] args) {
TestThread4 t = new TestThread4();
t.setDaemon(true);//守护线程主线程结束,则该线程结束
t.start();
System.out.println("main thread is exiting");
}
}
class TestThread4 extends Thread{
@Override
public void run() {
while (true){
System.out.println("TestThread4" + " is running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}