死锁
- 多个线程各自占有一些共享资源 并且相互等待其他线程占有的资源才能运行 而导致两个或者多个线程都在等待对方释放资源 都停止执行的情形 某一个同步块同时拥有两个以上对象的锁时,就有可能发生"死锁"问题
- 产生死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用
- 请求于保持条件:一个进程因请求资源而阻塞时, 对已获得的资源保持不放
- 不剥削条件: 进程已获得的资源 在未使用完之前 不能强行剥夺
- 循环等待条件: 若干进程之间形成一种头尾相接的循环等待资源关系
package com.wu.thread;
public class Demo20 {
public static void main(String[] args) {
new MakeUp(0,"小红").start();
new MakeUp(1,"小敏").start();
}
}
class Lipstick{}
class Mirror{}
class MakeUp extends Thread{
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice;
String girlName;
public MakeUp(int choice, String girlName){
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
makeUp();
}
private void makeUp(){
if(choice ==0){
synchronized (lipstick){
System.out.println(this.girlName + "用口红");
synchronized (mirror){
System.out.println(this.girlName + "用镜子");
}
}
}else {
synchronized (mirror){
System.out.println(this.girlName+ "用镜子");
synchronized (lipstick){
System.out.println(this.girlName + "用口红");
}
}
}
}
}
Lock(锁)
- 从JDK5.0开始 Java提供更强大的线程同步机制 通过显示定义同步锁对象来实现同步 同步锁使用Lock对象充当
- Lock接口是控制多个线程对共享资源进行访问的工具 锁提供了对共享资源的独占访问 每次只能有一个线程对Lock对象加锁 线程开始访问共享资源之间应先获得Lock对象
- ReentrantLock类实现类Lock
private final ReentrantLock lock = new ReentrantLock();
try{
lock.lock();
...
}finally{
lock.unlock();
}
线程协作
-
生产者消费模式
-
线程通信方法
- wait() 表示线程一直等待 直到其他线程通知 与sleep 不同 会释放锁
- wait(long timeout)指定等待毫秒数
- notify() 唤醒一个处于等待状态的线程
- notifyAll() 唤醒同一个对象上所有调用wait()方法的线程 优先级别高的线程优先调度
-
都是Object类的方法 都只能在同步方法或者异步代码块中使用 否则会抛出异常lllegalMonitorStateException
package com.wu.thread;
public class Demo24 {
public static void main(String[] args) {
Tv tv = new Tv();
new Player(tv).start();
new Audence(tv).start();
}
}
//演员
class Player extends Thread{
Tv tv;
public Player(Tv tv){
this.tv= tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2 ==0){
this.tv.show("还珠格格");
}else {
this.tv.show("西游记");
}
}
}
}
//观众
class Audence extends Thread{
Tv tv;
public Audence(Tv tv){
this.tv=tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
this.tv.watch();
}
}
}
//节目
class Tv {
String shower;
boolean flag = true;
public synchronized void show(String shower){
if(! flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演了:" + shower);
this.shower= shower;
this.notifyAll();
this.flag = !this.flag;
}
public synchronized void watch(){
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观众观看了:" + shower);
this.notifyAll();
this.flag = !this.flag;
}
}
使用线程池
-
提前创建好多个线程 放入线程池中 使用时直接获取 使用完放回池中 可以避免频繁创建销毁 实现重复利用. 类似公共交通工具
-
好处:
- 提高响应速度
- 降低资源消耗
- 便于线程管理
-
ExecutorService :真正的线程池接口 常见子类ThreadPoolExecutor
- void execute(Runnable command):执行任务/命令 没有返回值 一般用来执行Runnable
- submit(Callable):执行任务 有返回值 一般用来执行Callable
- void shutdown() :关闭连接池
-
Executors:工具类 线程池的工厂类 用于创建并返回不同类型的线程池
package com.wu.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo26 {
public static void main(String[] args) {
//创建线程池服务
ExecutorService service = Executors.newFixedThreadPool(10);
//开启服务
service.execute(new TestThread());
service.execute(new TestThread());
service.execute(new TestThread());
//关闭服务
service.shutdown();
}
}
class TestThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}