java线程浅析[初识线程]
前言:
本来这段时间学习的是C/C++一类的知识,知识最近看到了C一块的线程,因为是标准库函数提供的,所以理解和使用的时候其实要比java的线程相对要稍微难一点,而线程这一段,其实算是代码中相对比较难的一部分,所以想着还是把java的线程和C语言下一类的线程做一个整体性的总结学习,在两者的相互对比中,看到共同点,差异点,当然因为本人也是一个new coder,所以可能有一些总结的不对的地方,希望各位看官能够及时的指出。
首先还是简单介绍一下什么是线程吧
对比一下程序,进程以及线程
程序:就是安装在磁盘上的一个指令集合,是一种静态的概念
进程:运行中的程序,当然一个程序可能fork出很多子进程,进程算是程序的子集,她是一种动态的概念,而每个进程其实都是有自己的独立的资源
线程:又被称为轻量级的进程,也就是程序执行的最小单元,是程序中一个单一顺序控制的流程。线程是进程中的一个实体,它是被系统独立调度和分配的基本单位,也就是进程的子集
那什么有是多线程呢?
多线程:就是单个程序中可以同事运行多个不同的线程,通过这些不同的线程来执行不同的任务
多线程具有的特点:
1:一个进程同时包含一个或者多个线程
2:如果一个程序需要实现多个代码同时交替运行,那么这个时候就是需要产生多个线程
3:线程本身是不具有系统资源,而是与同属一个进程的其他线程共享了所在进程所拥有的资源
4:同一个进程的多个线程能够并发执行,cpu会随机抽出时间让我们的程序选择执行不同的功能代码
多线程的目的:
“最大的利用Cpu”就是多线程编程的主要目的
也是就当某个线程不需要占用cpu资源的时候,让需要占用cpu资源的线程有机会获取cpu资源
关于线程的创建方式
1:直接使用Thread去创建或者使用自定义的Thread
当一个普通的类去继承Thread类的时候,就能通过start方法去启动线程,执行线程中的run方法
Thread的子类能够实例话。但是子类中需要去掉super方法。不然可能会执行递交的task任务
2:一个类去实现Runable,然后再通过Thread去执行这个task
通过runable接口的类必须借助Thread类才能创建线程,
创建一个Runable接口类实例
创建一个Thread的对象,将第一步的Runable对象作为参数传入Thread中
通过Thread的start方法去启动执行
直接上代码
package com.zzf.demo.thread;
/**
* 注意Runable其实不是线程,它只是线程执行的一个task任务。所以真正的线程其实只有thread。
* runable只是一个接口而已,而我们如果去翻看相关源码的时候,其实就可以看到,Thread的父亲其实就是Runable
* @author dean
*
*/
public class MyThreadImplementsRunable implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("this is a MyCustomRunable implements Runable");
}
}
package com.zzf.demo.thread;
public class MyThreadExtendsThread extends Thread{
/**
* 无参数的构造方法
*/
public MyThreadExtendsThread() {
super();
}
/**
* @param target 任务
* @param name 线程名字
*/
public MyThreadExtendsThread(Runnable target, String name) {
super(target, name);
// TODO Auto-generated constructor stub
}
/**
* @param target 执行的任务
*/
public MyThreadExtendsThread(Runnable target) {
super(target);
// TODO Auto-generated constructor stub
}
/**
* @param name 线程名字
* 默认任务执行是会从线程本身的run方法中进行执行
*/
public MyThreadExtendsThread(String name) {
super(name);
// TODO Auto-generated constructor stub
}
/**
* @param group 将线程归属到某个线程组中去
* @param target 执行的runable任务
* @param name 线程名字
* @param stackSize 栈的大小
*/
public MyThreadExtendsThread(ThreadGroup group, Runnable target, String name, long stackSize) {
super(group, target, name, stackSize);
// TODO Auto-generated constructor stub
}
/**
* @param group 线程组
* @param target 目标task任务
* @param name 线程名字
*/
public MyThreadExtendsThread(ThreadGroup group, Runnable target, String name) {
super(group, target, name);
// TODO Auto-generated constructor stub
}
/**
* @param group 线程组
* @param target 目标task
*/
public MyThreadExtendsThread(ThreadGroup group, Runnable target) {
super(group, target);
// TODO Auto-generated constructor stub
}
/**
* @param group
* @param name
*/
public MyThreadExtendsThread(ThreadGroup group, String name) {
super(group, name);
// TODO Auto-generated constructor stub
}
@Override
public void run() {
// TODO Auto-generated method stub
//如果是super.run那么此时会调用runable中的方法,然后再去调自己的方法
System.out.println("this is a thread extends from thread");
}
}
package com.zzf.demo.thread;
public class ThreadTestMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThreadImplementsRunable customRunable = new MyThreadImplementsRunable();
//向线程去递交一个执行任务,
Thread thread =new Thread(customRunable);
thread.start();
MyThreadExtendsThread thread2 = new MyThreadExtendsThread();
//提交的是自定义的任务先执行自己本任务,然后线程再去执行自定义的任务,所以一般情况下都是由Thread递交task任务
//一般不会去用自定义的线程来执行特殊的task任务,因为二者之间往往可能会产生一些冲突
MyThreadExtendsThread thread3 = new MyThreadExtendsThread(customRunable);
//在开发的过程中建议给你的线程起一个名字,因为如果一旦遇到问题,更方便我们去定位是哪一个线程出现了问题
MyThreadExtendsThread thread4 = new MyThreadExtendsThread("myThread");
thread2.start();
thread3.start();
thread4.start();
}
}
当然这只是一个小小的Demo,主要就是讲怎么去创建线程,然而我们在实际的应用过程中,可能使用的时候为了图方便。调用方式五花八门。但是最终其实还是归根到原理性的一块
如:实际调用中可能出现的不规范,这种方式如果线程内部执行出错,可能定位稍微困难:
new Thread(){
public void run() {
System.err.println("this is a thread");
};
}.start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("this is a runable thread");
}
}).start();
在线程的使用过程中,还有很多方法,如使用线程池去递交我们 task等。会在后续的博客中持续更新,结合javaApi以及源码的形式。
以上就是关于线程的一点简单介绍,切合的并不是太深入。有兴趣的可以去看看javaApi以及Thread的源码,其实总的来说java的线程调用等,其实是在native层去做的,翻过源码的可以看到,在Thread类中,有很多native方法。这些都是通过结合C中的线程来执行的。