《图解Java多线程设计模式》之一:基础
一,什么是线程?
1.java中把正在执行程序的主体称为线程。
2.单线程:
当我们在阅读程序时,会根据处理流程来阅读,比如:首先执行前面的语句,然后再执行后面的语句,我们试着用笔将执行顺序描画出来,会发现描画出来的是一条弯弯曲曲的长线。这条长线始终是一条,无论调方法还是执行复杂的逻辑,对于这种处理流程始终如一条线的程序,称之为单线程程序。在单线程程序中,在某一个时间点执行的处理只有一个。
3.多线程
多个线程同时执行
3.应用场景
客户端应用程序
耗时的I/O处理
多个客户端:同时处理多个客户端
二,Thread类
1.启动线程必须使用线程类
public class MyThread extends Thread{ public void run(){ for(int i=0;i<100;i++){ System.out.println("hello"); } } }
新启动的线程的操作都编写在run方法中,新线程启动后,会调用run方法。当run方法执行结束后,线程也会跟着终止
2.启动一个线程
public class Main{ public static void main(String[] args){ MyThread t = new MyThread();//创建线程 t.start();//启动线程 for(int i = 0;i<100;i++){ System.out.println("world"); } } }
理解:上面代码中有两个线程,首先执行main方法,这个一个主线程。当执行到 t.start()时,会开启一个新的线程,该线程打印hello。
同时主线程继续向下执行,并打印world。这个程序运行着两个线程,所以这是一个多线程程序。
注意:启动线程调用的是start方法,不是run方法。当调用start方法后,程序会在后台启动新的线程。然后由这个新线程调用run方法。
start方法做了两件事,启动新线程,调用run方法
public class PrintThread extends Thread { private String message; public PrintThread(String message){ this.message = message; } public void run(){ for (int i = 0; i <1000 ; i++) { System.out.println(message); } } } -------------------------------------------------------------------- public class Test { public static void main(String[] args) { new PrintThread("aaa").start(); new PrintThread("bbb").start(); } } 这里新开启了两个线程,aaa和bbb交替打印 -------------------------------------------------------------------- public class Test { public static void main(String[] args) { new PrintThread("aaa").run(); new PrintThread("bbb").run(); } } 这里只是创建了两个对象,并调用对象的run方法,先打印aaa在打印bbb 注意上面的区别
三,创建线程的方式
1.继承Thread类
public class MyThread extends Thread{ public void run(){ for(int i=0;i<100;i++){ System.out.println("hello"); } } }
注意:Thread类本身实现了Runnable接口,并且持有run方法,但Thread类的run方法主体是空的,不执行任何操作。
Thread类的run方法通常由子类run方法重写。
2.实现Runnable接口
public class MyRunnable implements Runnable{ public void run(){ for(int i = 0;i<100;i++){ System.out.println("world"); } } } ---------------------------------------------------------- Runnable r = new MyRunnable(); Thread t = new Thread(r); t.start();
3.java.util.concurrent.ThreadFactory中的线程创建
public class Main{ public static void main(String[] args){ Runnable r = new MyRunnable(); ThreadFactory factory = Executors.defaultThreadFactory(); factory.newThread(r).start(); for(int i = 0;i<100;i++){ System.out.println("good"); } } }
四,线程的暂停
Thread.sleep();
sleep方法必须try...catch。因为sleep方法会抛出InterruptedException异常。InterruptedException异常能够取消线程的处理。
五,线程的互斥处理
防止多个线程同时操作同一个资源,引起结果和预期不相同。
1.synchronized方法
一个实例中的synchronized方法每次只能由一个线程运行。每个实例都拥有一个独立的锁。
synchronized方法的使用的是对象锁,synchronized静态方法使用的是类的类对象的锁(MyThread.class)。他们两个锁不一样
六,线程的协作
1.等待队列
所有实例拥有一个等待队列,他是在实例的wait方法执行后停止操作的线程的队列。就好比是为每一个实例准备的线程休息室
2.wait方法:把线程放入等待队列
执行了 obj.wait();当前线程就会暂停运行,并进入实例obj的等待队列中
注意:若要执行wait方法,线程必须持有锁。但如果线程进入等待队列,就会释放实例的锁
3.notify方法:从等待队列中取出线程
执行了obj.notify(); obj的等待队列的一个线程就会被选中和唤醒,然后就会退出等待队列。若要执行notify方法,线程也必须要持有调用的实例的锁
注意:notify唤醒的线程并不会在执行notify的一瞬间重新运行,因为在执行nofity的那一瞬间,执行notify的线程还持有锁,
其他线程还无法获取这个实例的锁
4.notifyAll方法:从等待队列中取出所有的线程
obj.notifyAll();
5.如果线程未持有锁的情况下调用wait,notify,notifyAll方法,会怎样?
抛异常:IllegalMonitorStateException
七,线程的状态转移
待续