标签:多线程
先理解一些概念
进程(process)常常被定义为程序的执行。 可以把一个进程看成是一个独立的程序,在内存中有其完备的数据空间和代码空间。一个进程所拥有的数据和变量只属于它自己。
线程(thread)则是进程中一个单独运行的程序,也就是说,线程是存在与进程之中的。
一个进程由一个或者多个线程构成,各个线程共享相同的代码和全局数据,但是每个线程都有自己独立的堆栈。
由于每个线程都有一个堆栈,所以局部变量对每个线程来说是私有的。
由于线程共享相同的代码和全局数据,线程比进程更紧密,比进程更趋向与相互作用,进程之间的通信通过全局数据。
一个进程和一个线程最显著的区别:是线程有自己的全局数据。线程存在于进程中,因此一个进程的全局变量由所有的线程共享。由于线程共享同样的系统区域,操作系统分配给一个进程的资源对该进程的所有线程都是可用的,正如全局数据可供所有线程使用一样
多线程:当有多部分代码需要同时运行时,就需要开辟多条执行路径来完成。
这时该程序就是多线程程序。
多线程解决了,让多部分代码同时运行的问题。开多了反而减低效率。
JVM中多线程
JVM中的多线程了解:
JVM中也一样是多线程程序,
只要有一个线程负责着程序的执行。
又有一个线程负责着垃圾的回收。
这个是同时进行的。
结论:
每一个线程都有自己的运行代码,这个称之为线程的任务。
对于每一个线程便于识别都有自己的名称。
比如负责从主函数执行程序代码的线程,称之为 主线程。main thread.
主线程运行的代码都定义在主函数中。
负责收垃圾的线程:垃圾回收线程。
class Test extends Object {
/*
重写了垃圾回收器调用的方法
*/
public void finalize()
{
System.out.println("test ok");
}
}
class Demo{
public static void main(String[] args) {
new Test();
new Test();
new Test();
new Test();
new Test();
System.gc(); //运行垃圾回收器
System.out.println("Hello World!1");
System.out.println("Hello World!2");
System.out.println("Hello World!3");
System.out.println("Hello World!4");
}
}
//调用了一次垃圾回收器。主线程是不执行new Test();主函数在没有调用System.gc();时的时候,只看到Hello World!,调用之后Hello World和test ok是随机排列,创建线程方式一-继承Thread
继承Thread类
1.子类覆盖父类中的run方法,将线程运行的代码存放在run中。
2.建立子类对象的同时,线程也被创建。
3.通过调用start方法开启线程。
class Demo extends Thread{
private String name;
Demo(String name){
this.name = name;}
public void run(){
for(int x=0; x<10; x++){
System.out.println("name...."+x+"....."+name);
}
}
}
class ThreadDemo {
public static void main(String[] args) {
//创建线程对象。
Demo d1 = new Demo("小强");
Demo d2 = new Demo("旺财");
//开启线程。让线程运行起来。
d1.start();
d2.start();
d1.run();
d2.run();
}
}调用run方法和调用start方法的区别?
调用run方法,从始至终都是主线程在运行。
调用start方法,是开启新的线程,新的线程运行run方法。
创建线程方式一 详解
每一个线程都应该有自己的任务,而且任务都会定义在指定的位置上。
主线程的任务都定义在main方法中。
自定义线程的任务都定义在了run方法中。
Thread t = new Thread();
t.start();
//这种开启只能调用Thread类中自己的run方法。而该run方法中并未定义自定义的内容。
我还需要创建线程,还要让线程执行自定义的任务。
所以可以复写run方法。前提必须是继承Thread类。
而继承了Thread后,该子类对象就是线程对象。
多线程-状态图解
临时阻塞状态是cpu并行执行多线程的时候,正在执行一种线程的时候,其他线程临时等待cpu。
sleep方法需要指定睡眠时间,单位是毫秒。sleep的时间结束的时候,就是冻结结束的时候。
Wait方法冻结线程之后是需要用notify方法唤醒。
从冻结状态恢复执行状态的线程可能会处于临时阻塞状态。
多线程-售票的例子
/*
需求:通过4个窗口将100票卖出。
*/
class Ticket extends Thread{
private int num = 100;
Public void run(){
sale();}
public void sale(){
while(true){
if(num>0){
System.out.println(Thread.currentThread().getName()+"..sale:"+num--);
}
}
}
}
class ThreadDemo3_Ticket {
public static void main(String[] args) {
//创建四个线程。
Ticket t1 = new Ticket();
//开启线程。
t1.start();
t1.start();
t1.start();
t1.start();
//多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。那该怎么办,下面介绍创建线程的第二种方式。
}
}创建线程的第二种方式-实现Runnable接口
创建线程的第二种方式。实现Runnable接口。
1,实现Runnable接口。
2,覆盖run方法。
3,通过Thread类创建线程对象。
4,将Runnable接口的子类对象作为实参传递给Thread类中的构造函数。
因为要让线程去运行指定的对象的run方法。
5,调用start方法开启线程,并运行Runnable接口子类的run方法。
class Ticket implements Runnable {
private int num = 100;
public void run(){ //线程任务
while(true){
if(num>0){
System.out.println(Thread.currentThread().getName()+"..sale:"+num--);
}
}
}
}
class ThreadDemo3_Ticket_Runnable{
public static void main(String[] args) {
Ticket t = new Ticket(); //t 是任务对象
Thread t1 = new Thread(t); //t1,t2,t3,t4 是线程对象
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
//多个线程对象调用同一个线程任务
}
}创建线程的第二种方式-实现Runnable接口原理
Thread里面是如何使用Runnable接口,其他程序是如何实现这个接口?
//下面是Thread里面的部分代码。
class Thread{
private Runnable target;
Thread(){ }
Thread(Runnable target){
this.target = target;
}
public void run(){
if(target!=null){
target.run();
}
}
public void start(){
run();}
}
class Student implements Runnable{
public void run(){ }
}
class Demo{
public static void main(String[] args) {
Student stu = new Student();
Thread t = new Thread(stu);
t.start();}
}创建线程的第二种方式-实现Runnable接口好处
第二种实现Runnable接口创建线程思想:
将线程任务和线程对象进行解耦,将线程任务单独封装成对象。
另外,实现Runnable接口可以避免单继承的局限性。
所以建议创建多线程,都是用实现Runnable接口的方式。
标签:多线程
原文地址:http://8477424.blog.51cto.com/8467424/1772832