1、多线程的概念
允许程序中并发执行多个指令流,每个指令流即为一个线程
2、创建多线程的四种方式
(1)继承Thread类,重写run方法
(2)实现Runable接口,实现run方法
(3)实现Callable接口,实现call方法。把callable实例作为FutureTask的属性创建task任务,然后创建线程
(4)通过线程池创建线程
3、线程的生命周期及状态转换
线程的五种状态:新建状态、就绪状态、运行状态、阻塞状态(不可运行状态)、死亡状态
(1)新建状态:当创建一个线程对象后,该对象处于新建状态,此时线程未开始运行。
(2)就绪状态:当线程对象调用start()方法后,线程进入就绪队列排队,等待被调度获得CPU资源
(3)运行状态:一但线程对象获得CPU资源,线程就调用自己的run()方法,进入运行状态。
完成任务 —进入–> 死亡状态
其他原因阻塞 —进入–> 阻塞状态
(4)阻塞状态:又称不可运行状态。引起线程进入阻塞状态的原因
(i)通过sleep(milliseconds)使线程进入休眠状态(可以通过已休眠的线程调用interrupt()方法退出休眠状态),在指定时间内线程不会运行
(ii)通过wait()方法使线程挂起。直到线程得到了notify()或notifyAll()消息,才会进入就绪状态
(iii)线程等待某个输入、输出的完成
(iiii)线程试图在某个对象上调用同步控制方法,但是对象锁不可用。因为另一个对象已经获得了这个锁
(5)死亡状态
(i)线程完成任务自然死亡
(ii)强制终止:如调用Thread的destroy()方法或stop()方法
4、线程的让步(yield)
当前运行的线程调用yield()方法,暂时放弃CPU,给其他线程一个执行的机会。yield()方法只会给相同或更高优先级的线程以执行的机会,所以调用yield()方法的线程不一定保证会放弃CPU。当所有线程中只有它优先级最高时,即使它调用了yield()方法也不会放弃CPU。
5、线程的联合(join)
一个线程A在占有CPU资源期间,可以让其他线程调用join()方法和本线程联合。如B.join(),称为A线程在运行期间联合了B线程。如果A线程在占有CPU资源期间一但联合B线程,那么A线程将立刻中断执行,一直等到它联合的线程B执行完毕,A线程再重新排队等待CPU资源。
6、线程的互斥
当多个线程竞争使用一个共享资源时如内存中的变量时,需要保证在一个时刻内只有一个线程操作该变量即互斥的访问和操作该变量。
临界区:即被竞争调用的一段程序段。也属于共享资源
synchronized:同步关键字。该关键字实现了线程互斥访问共享资源,确保任何时刻只能有一个线程对共享资源进行访问和操作。可以修饰一段程序段或一个方法,相当于给临界区加锁。
对象的wait()方法:当线程拥有该对象的锁,在同步代码块中调用该对象的wait()方法,当前线程释放该“对象锁”,进入阻塞状态,Java系统将当前线程放入该对象的等待队列。
对象的notify()方法:当另外一个线程调用该对象的notify()或者notifyAll(),释放该对象的锁。notify唤醒任意一个线程,从中断处继续执行。notifyAll()唤醒所有在该对象上等待的线程,按照“先中断先执行”原则选择最先中断的线程继续在该对象中断处执行。
7 、守护线程
一个线程通过调用他的setDaemon(boolean on)为true时,设置自己为一个守护线程。
当所有非守护线程运行结束,即使守护线程的run方法中还有未执行的语句,也会理科结束运行。
8、线程间的通信
Java线程间的通信是通过管道流来实现的。一个线程发送数据到输入管道,另一个线程从输出管道中读数据。管道用来把一个线程或代码块的输出连接到拎一个线程或代码块中
Java线程间的通信是通过管道流PipeOutputstream和PipeInputStream来实现的,代码如下:
//发送方
public class Sender implements Runnable {
private PipedOutputStream out = new PipedOutputStream();
public PipedOutputStream getPipeOutputStream(){
return this.out;
}
@Override
public void run() {
String s = "这是管道输出流发送过来的数据";
try {
out.write(s.getBytes());
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//接收方
public class Receiver implements Runnable{
private PipedInputStream in;
public Receiver(Sender sender){
try {
in = new PipedInputStream(sender.getPipeOutputStream());
//创建管道输入流类对象,实现管道流的连接
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
byte[] b = new byte[1024];
try {
int count = 0;
while((count=in.read(b))!=-1){
String s = new String(b, 0, count);
System.out.println(s);
}
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
Sender sender = new Sender();
Receiver receiver = new Receiver(sender);
Thread senderThreader = new Thread(sender);
Thread receiverThreader = new Thread(receiver);
senderThreader.run();
receiverThreader.run();
}
}