1.什么是进程
程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
进程是一个具有一定独立功能的程序,一个实体,每一个进程都有它自己的地址空间。
2.进程的状态
进程执行时的间断性,决定了进程可能具有多种状态。事实上,运行中的进程具有以下三种基本状态。
就绪状态、运行状态、阻塞状态
3.什么是线程
线程实际上是在进程基础上的进一步划分,一个进程启动之后,里面的若干程序又可以划分成若干线程。
线程是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程(单线程程序)
一个程序可以同时执行多个任务,来提高效率。例如:同时下载多个电影、同时与多人聊天
并行:两个任务同时运行(多个CPU)
并发:两个任务同时请求运行,而处理器一次只能接受一个任务,就会把两个任务安排轮流执行,由于CPU时间片运行时间较短,就会感觉两个任务在同时执行。
4.线程的基本使用
方法一:继承Thread类
public class Demo2 {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start(); //启动线程
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i <50 ; i++) {
System.out.println("");
}
}
}
运行效果:
方法二:实现Runnable接口
public class Demo2 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t2 = new Thread(mr);
t2.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i <50 ; i++) {
System.out.println(Thread.currentThread().getName()+"-"+i);
}
}
}
更加推荐使用第二种方法,实现Runnable接口创建多线程与继承Thread类相比优点是:
1.避免了继承Thread类的单继承的局限性。
【类只能单继承,类继承了Thread类就不能继承其他的类
而实现了Runnable接口,还可以继承其他的类,实现其他的接口
】
2.实现Runnable接口降低了线程对象和线程任务的耦合性,增强了程序的可扩展性。
【实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(实现解耦)
实现类中,重写了run方法来设置线程任务
创建Thread类对象,调用start方法来开启新线程
创建Thread类对象,构造方法中传递Runnable接口的实现类对象,可以传递不同的实现类(可扩展性)
】
3.实现Runnable接口将线程单独进行对象的封装,更符合面向对象思想。
参考:多线程之实现Runnable接口及其优点 - 初仰 - 博客园
5.线程的休眠
在当前线程的执行中,暂停指定的毫秒数,释放CPU的时间片
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
示例代码:
public class Demo2 {
public static void main(String[] args) {
MyThread mt = new MyThread();
MyRunnable mr = new MyRunnable();
Thread t2 = new Thread(mr);
mt.start(); //启动线程
t2.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i <50 ; i++) {
System.out.println(Thread.currentThread().getName()+"-"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i <50 ; i++) {
System.out.println(Thread.currentThread().getName()+"-"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行效果:6.线程的一些函数
Thread.currentThread():返回对当前正在执行的线程对象的的引用
Thread.currentThread().getName():获取当前线程的名称
7.join与中断线程
1.join
public final void join() throws InterruptedException:等待这个线程死亡,调用此方法的行为方式与调用完全相同。
join:加入线程,让调用的线程先执行指定时间或执行完毕。
异常 InterruptedException:如果任何线程中断当前线程,当抛出此异常时,当前线程的中断状态将被清除。
public class ThreadDemo2 {
public static void main(String[] args) {
MyRunnable2 mr2 =new MyRunnable2();
Thread t =new Thread(mr2);
t.start();
for (int i =0; i <50; i++) {
System.out.println(Thread.currentThread().getName() +"-"+i);
try {
Thread.sleep(300);
}catch (InterruptedException e) {
e.printStackTrace();
}
if(i==20)
{
try {
t.join(); //让t线程执行完毕,再执行main
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyRunnable2implements Runnable {
@Override
public void run() {
for (int i =0; i <50; i++) {
System.out.println(Thread.currentThread().getName() +"-"+i);
try {
Thread.sleep(300);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
执行结果:main线程和t线程开始一起执行,在main线程执行到20时,t线程一个人执行,待t线程执行完毕之后再开始执行main线程。
运行效果:
2.中断线程
方法一:使用interrupt方法来中断线程,设置一个中断状态(标记),需要注意sleep等方法会清除标记,需要相应的处理才能实现中断。
此方法需要修改三处代码,需要写判断,不推荐使用。
public void interrupt():
异常 InterruptedException:如果任何线程中断当前线程,当抛出此异常时,当前线程的中断状态将被清除。
public class ThreadDemo2 {
public static void main(String[] args) {
MyRunnable2 mr2 =new MyRunnable2();
Thread t =new Thread(mr2);
t.start();
for (int i =0; i <50; i++) {
System.out.println(Thread.currentThread().getName() +"-"+i);
try {
Thread.sleep(300);
}catch (InterruptedException e) {
e.printStackTrace();
}
if(i==20)
{
t.interrupt(); //中断线程,只是做了一个中断标记,
}
}
}
}
class MyRunnable2implements Runnable {
@Override
public void run() {
for (int i =0; i <50; i++) {
if(Thread.interrupted())//测试中断状态,此方法会把中断状态清除
{
break;
}
System.out.println(Thread.currentThread().getName() +"-"+i);
try {
Thread.sleep(300);
}catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}
运行效果:
方法二:自定义标记的方式,更好控制,更加推荐使用。
public class ThreadDemo2 {
public static void main(String[] args) {
MyRunnable3 mr3 =new MyRunnable3();
Thread t2 =new Thread(mr3);
t2.start();
for (int i =0; i <50; i++) {
System.out.println(Thread.currentThread().getName() +"-"+i);
try {
Thread.sleep(300);
}catch (InterruptedException e) {
e.printStackTrace();
}
if(i==20)
{
mr3.flag =false;
}
}
}
}
class MyRunnable3implements Runnable{
public boolean flag =true;
//构造方法
public MyRunnable3()
{
flag =true;
}
@Override
public void run() {
int i =0;
while (flag)
{
System.out.println(Thread.currentThread().getName()+"-"+(i++));
try {
Thread.sleep(300);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行效果:
7.守护线程
public class ThreadDemo2 {
public static void main(String[] args) {
MyRunnable3 mr3 = new MyRunnable3();
Thread t2 = new Thread(mr3);
t2.setDaemon(true);
t2.start();
for (int i =0; i <50; i++) {
System.out.println(Thread.currentThread().getName() +"-"+i);
try {
Thread.sleep(200);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyRunnable3 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"-"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行效果:
主线程运行结束之后,设置为守护线程的t线程也结束了。
8.其他方法与优先级
getId():返回该线程的标志符
getName():返回该线程的名称
setName():改变线程的名称
isAlive():测试线程是否处于活动状态
setPriority(int newPriority):更改线程优先级,可选MAX_PRIORITY、MIN_PRIORITY/NORM_PRIORITY