面试的时候总是会提及到这个关于线程的问题。(自己根据看到的资料和自己的理解想到的,大概会有不全的地方)
说到线程,首先说一下进程。
进程:运行中应用程序,享有系统资源(CPU等)。比如大家正在用的QQ,它就是一个进程。
线程:进程中的一段代码,一个进程有多个线程。如何大家使用QQ这个进程,那么你听音乐和聊天就是两个线程,从宏观上看是同时执行的,实际上不是。这就是并发。
①线程是如何创建的:
1)通过继承Thread类来实现,重写run方法,通过new Thread()来创建线程的实例化对象,调用start()方法就可以启动一个线程
2)通过实现Runnable接口是实现,重写run方法,通过new Thread(new Runnable)来创建线程的实例化对象,调用start()方法启动线程。
Thread类实现了Runnable接口。
②线程的状态转换
1)新建状态,new实例化线程对象
2)就绪状态 ,当调用start()方法之后,线程就进入就绪状态
3)可运行状态,这个状态比较重要。当cpu分配资源的时候,就可以进入可运行状态,执行run()方法。
可运行到就绪:时间片完了。或者是调用了yield()方法,也可以从可运行到就绪。
可运行到阻塞:调用sleep()方法,等待I/O。
可运行到死亡:程序在运行过程中遇到异常,调用stop()和destroy()方法。
sleep()和wait()方法的区别:
sleep是占用cpu资源,但是不工作,其他线程不能占用该CPU,OS会认为该线程正在工作,不会让出系统资源
wait是到等待池进行等待,让出系统资源。
③多线程
多线程,顾名思义就是多个线程同时运行。
涉及到的问题有 同步、死锁
比如线程A和线程B,要进行通信,并且对数据结构进行读写,比如链表。线程A要对链表进行读的操作,线程B要对链表进行写的操作,那么可能造成数据不安全。
应该要实现什么呢?当线程A对链表进行操作的时候,线程B不可以链表进行操作,只有到线程A释放了锁之后,别的线程才可以进行操作
1)同步互斥:多个并发执行的线程在在某一个时间段内只能有一个线程对数据进行操作。
同步的方法:
1>synchronized修饰方法
2>synchronized修饰代码块
3>特殊变量域 volatile
4>ThreadLocal类
比如一个例子:
火车票卖票,有两个窗口,如何实现数据共享
package com.ljq.test;
/**
* 使用Runnable接口模拟4个售票窗口共同卖100张火车票的程序
*
* 共享数据,4个线程共同卖这100张火车票
* @author jiqinlin
*
*/
publicclass RunnableTest {
publicstaticvoid main(String[] args) {
Runnable runnable=new MyThread();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
public static class MyThread implements Runnable{
//车票数量
private int tickets=100;
publicvoid run() {
while(tickets>0){
System.out.println(Thread.currentThread().getName()+"卖出第【"+tickets--+"】张火车票");
}
}
}
}
实际工作中,几乎所有的多线程应用都用实现Runnable这种方式。