JAVA--线程


进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。简单来说:进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。

 

线程是指进程中的一个执行流程,一个程序内部的顺序控制流。一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

进程是资源分配的最小单位,线程是执行的最小单位

 

线程和进程的区别


1,每个进程都有独立的代码和数据空间,进程间的切换会有较大的开销

2,线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器,线程切换的开销小

3,多进程:在操作系统中能同时运行多个任务(程序)

4,多线程:在同一应用程序中有多个顺序流同时执行

 

线程与进程对比-不错的博文:

http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html

 

java的线程


是通过java.lang.Thread类来实现的

VM启动时会有一个由主方法(public static void main(){})所定义的线程。

可以通过创建Thread的实例来创建新的线程

每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体

通过调用Thread类的start()方法来启动一个线程

 

线程的创建和启动(两种方式)


1,可以定义一个Thread的子类并重写其run方法


示例:

public class MultiThreadDemo {

    public static void main(String [] args){

        MultiThread m1=new MultiThread("Window 1");

        MultiThread m2=new MultiThread("Window 2");

        MultiThread m3=new MultiThread("Window 3");

        m1.start();

        m2.start();

        m3.start();

    }

}

class MultiThread extends Thread{

    private int ticket=100;//每个线程都拥有100张票

    MultiThread(String name){

        super(name);//调用父类带参数的构造方法

    }

    public void run(){

        while(ticket>0){

            System.out.println(ticket--+" is saled by "+Thread.currentThread().getName());

        }

    }

}



程序中定义一个线程类,它扩展了Thread类。利用扩展的线程类在MutliThreadDemo类的主方法中创建了三个线程对象,并通过start()方法分别将它们启动。

 

从结果可以看到,每个线程分别对应100张电影票,之间并无任何关系,这就说明每个线程之间是平等的,没有优先级关系,因此都有机会得到CPU的处理。但是结果显示这三个线程并不是依次交替执行,而是在三个线程同时被执行的情况下,有的线程被分配时间片的机会多,票被提前卖完,而有的线程被分配时间片的机会比较少,票迟一些卖完。

 

可见,利用扩展Thread类创建的多个线程,虽然执行的是相同的代码,但彼此相互独立,且各自拥有自己的资源,互不干扰。

 

2,定义线程类实现Runable接口


示例:

public class MultiThreadDemo2 {

    
 public static void main(String [] args){

        MultiThread m1=new MultiThread("Window 1");

        MultiThread m2=new MultiThread("Window 2");

        MultiThread m3=new MultiThread("Window 3");

        Thread t1=new Thread(m1);

        Thread t2=new Thread(m2);

        Thread t3=new Thread(m3);

        t1.start();

        t2.start();

        t3.start();

    }
}

class MultiThread implements Runnable{

    private int ticket=100;//每个线程都拥有100张票

    private String name;

    MultiThread(String name){

        this.name=name;

    }

    public void run(){

        while(ticket>0){

            System.out.println(ticket--+" is saled by "+name);

        }

    }

}



由于这三个线程也是彼此独立,各自拥有自己的资源,即100张电影票,因此程序输出的结果和(1)结果大同小异。均是各自线程对自己的100张票进行单独的处理,互不影响。

 

可见,只要现实的情况要求保证新建线程彼此相互独立,各自拥有资源,且互不干扰,采用哪个方式来创建多线程都是可以的。因为这两种方式创建的多线程程序能够实现相同的功能。

  

对比:


在Java中,类仅支持单继承,也就是说,当定义一个新的类的时候,它只能扩展一个外部类.这样,如果创建自定义线程类的时候是通过扩展Thread类的方法来实现的,那么这个自定义类就不能再去扩展其他的类,也就无法实现更加复杂的功能。因此,如果自定义类必须扩展其他的类,那么就可以使用实现Runnable接口的方法来定义该类为线程类,这样就可以避免Java单继承所带来的局限性。

 

还有一点最重要的就是使用实现Runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享.


例如:


假如当日从A地发往B地的火车票只有100张,且允许所有窗口卖这100张票,那么每一个窗口也相当于一个线程,但是这时和前面的例子不同之处就在于所有线程处理的资源是同一个资源,即100张车票。


public class MultiThreadDemo3 {

    public static void main(String [] args){

        MultiThread m=new MultiThread();

        Thread t1=new Thread(m,"Window 1");

        Thread t2=new Thread(m,"Window 2");

        Thread t3=new Thread(m,"Window 3");

        t1.start();

        t2.start();

        t3.start();

    }

}

class MultiThread implements Runnable{

    private int ticket=100;

    public void run(){

        while(ticket>0){

            System.out.println(ticket--+" is saled by "+Thread.currentThread().getName());

        }

    }

}



采用继承Thread类方式:

(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。

(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。

采用实现Runnable接口方式:

(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况。

(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

 

 

线程同步:


java语言中,引入了对象互斥锁的概念,保证共享数据操作的完整性。每个对象都对应于一个可称为“互斥锁”的标记,这个标记保证在任一时刻,只能有一个线程访问该对象。

关键字synchronized来与对象的互斥锁联系。当某个对象synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。


示例:

public class TestSync implements Runnable{
	Timer timer=new Timer();
	public static void main(String[] args){
		TestSync test=new TestSync();
		Thread t1=new Thread(test);
		Thread t2=new Thread(test);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
		}
		public void run(){
			timer.add(Thread.currentThread().getName());
			}
}
class Timer{
	private static int num=0;
	public synchronized void add(String name){
		num++;
		try{
			Thread.sleep(1);
		}catch(InterruptedException e){
			
			}
			System.out.println(name+",你是第"+num+"个使用timer的线程");
		}
	}



去掉synchronized,显示结果并不是我们想要的,所以有时我们需要同步执行,即有序执行!




总结:


    对于一个CPU来说,无论我创建多少个线程,所谓的“并发执行”、“同时”其实都不是真正意义上的“同时”。操作系统将进程线程进行管理,轮流(没有固定的顺序)分配每个进程很短的一段时间(不一定是均分),然后在每个线程内部,程序代码自己处理该进程内部线程的时间分配,多个线程之间相互的切换去执行,这个切换时间也是非常短的。因此多任务、多进程、多线程都是操作系统给人的一种宏观感受,从微观角度看,程序的运行是异步执行的。虽然操作系统是多线程的,但CPU每一时刻只能做一件事!



  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值