wait\notify
package 线程安全问题;
/*
* 案例:线程之间的通信
* 创建一个顾客线程:告知老板要的包子的种类和数量,调用wait方法放弃cpu的执行,进入到WAITING状态(无限等待)
* 创建一个老板线程:花了5秒做包子,做好包子之后,调用notify方法,唤醒顾客吃包子
*
* 注意:
* 顾客和老板必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行
* 同步使用的锁必须保证唯一
* 只有锁对象才能调用wait和notify方法
* Object类中的方法:
* void wait()
* 在其他线程中调用此对象的notify()方法或notifyAll()方法,导致当前线程等待
* void notify()
* 唤醒在此对象监视器上等待的单个线程
* 会继续执行wait方法之后的代码
*
* */
public class Demo04 {
public static void main(String[] args) {
//创建锁对象,唯一
Object obj = new Object();
//创建一个顾客线程
new Thread() {
@Override
public void run() {
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("告知老板包子的数量和种类");
//调用wait()方法,放弃cpu的执行进入WAITING状态(无限等待)
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后,继续执行的代码
System.out.println("包子已经做好了,开吃!");
}
}
}.start();
//******************************************************
//创建一个老板线程
new Thread(){
@Override
public void run() {
synchronized (obj) {
//先睡眠5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子");
//做好包子之后,调用notify方法,唤醒顾客吃包子
obj.notify();
}
}
}.start();
}
}
notifyALL()与notify()区别
package 线程安全问题;
/*
* 进入到Timewaiting(计时等待)的两种方式:
* 1.使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Blocked状态
* 2.使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程睡醒进入到Runnable/Blocked状态
* 唤醒的方式:
* void notify()唤醒在此对象监视器上等待的单个线程
* void notifyAll()唤醒在此对象监视器上等待的所有线程
*
*
* */
public class Demo05 {
public static void main(String[] args) {
Object obj = new Object();
new Thread() {
@Override
public void run() {
while (true) {
synchronized (obj) {
System.out.println("顾客1告知老板包子的数量和种类");
//调用wait()方法,放弃cpu的执行进入WAITING状态(无限等待)
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后,继续执行的代码
System.out.println("包子已经做好了,顾客1开吃!");
}
}
}
}.start();
new Thread() {
@Override
public void run() {
while (true) {
synchronized (obj) {
System.out.println("顾客2告知老板包子的数量和种类");
//调用wait()方法,放弃cpu的执行进入WAITING状态(无限等待)
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后,继续执行的代码
System.out.println("包子已经做好了,顾客2开吃!");
}
}
}
}.start();
//创建一个老板线程
new Thread(){
@Override
public void run() {
while (true) {
//先睡眠5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子");
//做好包子之后,调用notify方法,唤醒顾客吃包子
//obj.notify(); //随机唤醒一个线程
obj.notifyAll(); //唤醒所有等待的线程
}
}
}
}.start();
}
}
线程池
package 线程安全问题;
//2.创建一个类,实现Runnable接口,重写run方法设置任务
public class Imp implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建了一个新的线程");
}
}
package 线程安全问题;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
*
* java.util.concurrent.Executors:线程池的工厂类,用来生产线程
* 其静态方法:
* static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
* 返回值:ExecutorService接口,返回的是ExecutorService接口的实现类对象
*
* java.util.concurrent.ExecutorService:线程池接口
* 用来从线程池中获取线程,调用start方法,执行线程任务
* submit(Runnable task)提交一个 Runnable 任务用于执行。
* 关闭销毁线程
* void shutdown() 启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
*
* 线程池的使用步骤:
* 1.使用线程池的工厂类中static ExecutorService newFixedThreadPool(int nThreads):创建一个指定线程数量的线程池
* 2.创建一个类,实现Runnable接口,重写run方法设置任务
* 3.调用ExecutorService中的submit(Runnable task),传递线程任务,开启线程,执行run方法
* 4.调用shutdown(),销毁线程池(不建议)
*
* */
public class Demo06Executors {
public static void main(String[] args) {
//1.使用线程池的工厂类中static ExecutorService newFixedThreadPool(int nThreads):创建一个指定线程数量的线程池
ExecutorService es = Executors.newFixedThreadPool(2);
//3.调用ExecutorService中的submit(Runnable task),传递线程任务,开启线程,执行run方法
es.submit(new Imp());
es.submit(new Imp());
es.submit(new Imp());
es.shutdown();
}
}