线程通信
涉及到的三个方法:
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
notify():一旦执行此方法,就会唤醒被wait的一个线程。 如果有多个线程被wait, 就唤醒优先级高的。
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
示例代码:
public class test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
thread1.setName("线程1");
thread2.setName("线程2");
thread1.start();
thread2.start();
}
}
class MyThread implements Runnable {
private int number = 0;
@Override
public void run() {
synchronized (this){
while (number <= 100){
notifyAll();
System.out.println(Thread.currentThread().getName()+":"+number);
number++;
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
- wait(), notify(), notifyAll()三个方法必须使用在同步代码块或同步方法中。
- wait(), notify(), notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器,否则,会出现ILlegaLMonitorStateException异常
- wait(), notify(), notifyALl()三个方法是定义在java. lang. object类中。
线程通信应用:生产者/消费者问题
示例代码
public class test{
public static void main(String[] args) {
Clerk clerk = Clerk.ReturnClerk();
Producer producer = new Producer(clerk);
Consumer consumer = new Consumer(clerk);
Thread thread = new Thread(producer);
Thread thread1 = new Thread(consumer);
thread.start();
thread1.start();
}
}
class Clerk {
int ticket = 0;
private static ReentrantLock lock = new ReentrantLock();
private static Clerk clerk = null;
private final Object object = new Object();
private Clerk() {
}
public static Clerk ReturnClerk() {
if (clerk == null) {
try {
lock.lock();
if (clerk == null) {
clerk = new Clerk();
}
} finally {
lock.unlock();
return clerk;
}
} else {
return clerk;
}
}
void producerMethod(){
synchronized (object) {
if (ticket < 20) {
ticket++;
System.out.println(Thread.currentThread().getName() + ':' + "正在生产第" + ticket + "张票");
object.notify();
}
else{
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
void consumerMethod(){
synchronized (object) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ':' + "正在消费第" + ticket + "张票");
ticket--;
object.notify();
}
else{
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class Producer implements Runnable{
private Clerk clerk;
public Producer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
while (true) {
this.clerk.producerMethod();
}
}
}
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
while (true) {
this.clerk.consumerMethod();
}
}
}
JDK5.0之后的创建线程方法
Callable接口
如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?
- call()可以有返回值的。
- call()可以抛出异常,被外面的操作捕获,获取异常的信息
- Callable是支持泛型的
public class test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
FutureTask futureTask = new FutureTask(myThread);
new Thread(futureTask).start();
try {
Object sum = futureTask.get();
System.out.println("总和为"+sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyThread implements Callable{
int number = 0;
@Override
public Object call() throws Exception {
int total = 0;
while (number <= 100){
if (number % 2 == 0){
total += number;
System.out.println(number);
}
number++;
}
return total;
}
}
线程池
背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
思路:提前创建好多个线程,放入线程酒中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处:
1.提高响应速度(减少了创建新线程的时间)
2.降低资源消耗(重复利用线程池中线程,不需要每次都创建)
3.便于线程管理
JDK 5.0起提供了线程池相关API: ExecutorService 和Executors
ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
➢void execute(Runnable command):执行任务1命令,没有返回值,一般用来执行Runnable
➢ Future submit(Callable task): 执行任务,有返回值,一 般又来执行Callable
➢void shutdown() :关闭连接池
Executors: 工具类、线程池的工厂类,用于创建并返回不同类型的线程池
➢Executors.newCachedThreadPool(): 创建一个可 根据需要创建新线程的线程池
➢Executors .newFixedThreadPool(n);创建一个可 重用固定线程数的线程池
➢Executors.newSingleThreadExecutor():创建一个 只有一-个线程的线程池
➢Executors.newScheduledThreadPool(n): 创建一个线程池, 它可安排在给定延迟后运行命令或者定期地执行。
public class test{
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new MyThread());
executorService.execute(new MyThread1());
executorService.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
int number = 0;
while (number <= 100){
if (number % 2 == 0){
System.out.println(number);
}
number++;
}
}
}
class MyThread1 implements Runnable{
@Override
public void run() {
int number = 0;
while (number <= 100){
if (number % 2 != 0){
System.out.println(number);
}
number++;
}
}
}
如果需要设置线程池的一些属性
public class test{
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
ThreadPoolExecutor server = (ThreadPoolExecutor)executorService;
server.setCorePoolSize(10);
server.execute(new MyThread());
server.execute(new MyThread1());
executorService.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
int number = 0;
while (number <= 100){
if (number % 2 == 0){
System.out.println(number);
}
number++;
}
}
}
class MyThread1 implements Runnable{
@Override
public void run() {
int number = 0;
while (number <= 100){
if (number % 2 != 0){
System.out.println(number);
}
number++;
}
}
}