Java笔记五.多线程

Java中的多线程(一)

一、理解线程

1.进程、线程、多线程

1.进程:在多任务系统中,每个独立执行的程序(或说正在进行的程序)称为进程。

2.线程:一个进程中又可以包含一个或多个线程,一个线程就是一个程序内部的一条执行线索(一部分代码)。

3.多线程:如果要一程序中实现多段代码同时交替运行,就需产生多个线程,并指定每个线程上所要运行的程序代码,即为多线程。

注:在单线程中,程序代码的执行是按调用顺序依次往下执行的,不能实现两端程序代码同时交替运行的效果。当我们的程序启动运行时,会自动产生一个线程,主函数mian就是在这个线程上运行的,当不再产生新的线程时,程序就是单线程的。所以,在这种情况下,该程序进程也就是主线程。

2.Thread类

(1)构造方法

Thread():创建一个线程对象
Thread(Runnable target):创建一个带Runnabke对象参数的线程对象
Thread(Runnable target, String name):创建一个带Runnable对象参数的线程对象
Thread(String name):创建一个线程对象,并指定线程的名称

Allocates a new Thread object.

(2)主要方法

static Thread currentThread():返回当前执行的是哪个线程对象

long getId():返回该线程的ID

String getName() :返回该线程的名称

int getPriority():返回该线程的优先级

void interrupt():打断该线程

boolean isAlive() :判定该线程是否为活动状态

boolean isDaemon():判断该线程是否为守护进程

void join():合并线程

void join(long millis):等待线程millis毫秒,然后分离到合并前状态

void run():当线程运行时,Runnale对象的run()方法被调用来执行相关代码

void setDaemon(boolean on):设置该线程为守护进程

void setName(String name) :设置更改该线程的名称为name

void setPriority(int newPriority):设置改变该线程的优先级(MAX_PRIORITY/MIN_PRIORITY/NORM_PRIORITY)

static void sleep(long millis):该方法使正在执行的线程进入睡眠状态且释放占用的CPU控制权,待millis毫秒后该线程重新被唤醒且再次获得CPU的控制权

void start():线程被创建后,调用该方法启动该线程,Java虚拟机调用线程的run方法

3.Runnable接口

(1)功能如果我们定义一个类打算通过一个线程来执行的话,可以通过使该类继承这个Runnable接口并且在类中实现一个无参数的run()方法。继承于Runnable接口的类无需再继承Thread类,只需实例化该类的一个对象将其作为Thread对象参数即可实现在一个线程内运行自定义类代码。

(2)方法

void run():当一个对象继承于Runnable接口被用于创建一个线程,启动该线程将会是我们定义类中的run方法将会在一个单独的线程中执行。

二、创建线程的两种方法

Java中创建多线程主要有两种方法:继承Thread类和实现Runnable接口。

1.用Thread类创建线程

(1)原理

Java的线程是通过java.lang.Thread类来控制的,一个Thread类的对象代表一个线程,而且只能代表一个线程,通过Thread类和它定义的对象,我们可以获得当前线程对象、设置线程的优先级或获取某一线程的名称或者控制线程暂停一段时间等功能。

(2)开发思路

a.实现一个类,使该类继承于Thread类;

b.实现该类的run()方法,用于实现我们希望线程要完成的任务;

c.实例化该类一个对象,调用其start()方法启动该线程。

(3)源码举例

//主线程
public class DemoThread
{
 public static void main(String arg[])
 {
  TestThread thread = new TestThread();	//创建一个Thread子类对象
  thread.start();	//启动该子线程
  while(true)
  {
   System.out.println("main thread is running.");
  }
 }
}

//子线程的类
class TestThread extends Thread
{
 public void run() {
  while(true)
  {
   System.out.println(Thread.currentThread().getName()+" is running.");
  }
 }
}

分析:通过观察程序运行情况可知,程序有两个线程(多线程)无规律的交替运行。

效果:


升华笔记1:

1.要实现多线程,我们必须编写一个继承了Thread类的子类,子类必须覆盖Thread类中的run()方法,并且在子类的run方法中编写我们希望在新线程上实现的功能代码;

2.启动一个新的线程不是直接调用Thread子类对象的run()方法,二是调用Thread子类对象的start()方法,Thread类对象的start方法将产生一个新的线程,并在该线程上运行该Thread类对象中的run方法。

3.由于线程的代码段在run方法中,当run()方法执行完成后,相应的线程也就结束了,所以我们可以通过控制run方法中的循环条件来控制线程的终止。



2.使用Runnable接口创建多线程

(1)原理

当使用Thread(Runnale target)方法创建线程对象时,需为该方法传递一个实现了Runnable接口的类对象,这样创建的线程将调用哪个实现了Runnable接口的类对象中的run()的方法作为其运行代码,而不在调用Thread类中的run方法。

(2)开发思路

a.实现一个类,该类继承于Runnable接口并覆盖实现Runnable接口的run()方法;

b.实例化该类一个对象,并将该对象作为参数实例化一个Thread类对象;

c.调用Thread类的start()方法启动该子线程;

(3)源码举例

//主线程
public class RunnableTest {
 public static void main(String args[])
 {
  TestRunnable runnable = new TestRunnable();	//创建一个类对象,该类继承于Runnable接口
  Thread thread=new Thread(runnable);	//创建一个带Runnable对象参数的线程
  thread.start();	//启动该线程
  while(true)
  {
   System.out.println("main thread is running.");
  }
 }
}
//子线程
class TestRunnable implements Runnable
{
 @Override
 public void run() {
  while(true)
  {
   System.out.println(Thread.currentThread().getName()+" is running.");
  }
 }

}

效果:

3.两种实现多线程方式的对比分析

通过上述两个例子,我们知道继承Thread类和实现Runnable接口都能实现多线程,并且也未看出两者有何区别。但是,当我们希望开发的多线程去处理同一资源(一个资源只能对应一个对象)时,继承Thread类方式就有点力不从心了。

举个例子:通过程序来模拟铁路售票系统,实现通过四个售票点发售某日某次列车的100张车票,一个售票点用一个线程来表示。

(1)继承Thread类方式的多线程

//主线程
public class SaleTickets {
 public static void main(String[] arg)
 {
  new Resource().start();//启动线程1
  new Resource().start();//启动线程2
  new Resource().start();//启动线程3
  new Resource().start();//启动线程4

 }
}
//唯一资源
class Resource extends Thread
{
 private int tickets=100;	//100张票
 @Override
 public void run() {	 //线程每运行一次run方法,票数减1
  while(tickets>0)
  {
    System.out.println(Thread.currentThread().getName()+" is saling tickets "+tickets--);
  }
 }

}

分析:观察结果,我们知道在主线程中创建的四个线程各自卖各自的100张票,而不是去卖共同的100张票,也就是说这几个线程去处理的不是同一资源!实际上,在上面的程序中,我们创建了四个 Resource对象,就等于创建了四个资源,每个
Resource对象中都有100张票,每个线程在独立地处理各自的资源。

效果:

(2)继承Runnable类方法的多线程

//主线程
public class SaleTickets {
 public static void main(String[] arg)
 {
  Resource r = new Resource();	//实例化一个Runnbale子类对象,代表一个资源
  /*依次创建4个子线程*/
  new Thread(r).start();
  new Thread(r).start();
  new Thread(r).start();
  new Thread(r).start();

 }
}
//唯一资源
class Resource implements Runnable
{
 private int tickets=100;	//100张票
 @Override
 public void run() {	 //线程每运行一次run方法,票数减1
  while(tickets>0)
  {
    System.out.println(Thread.currentThread().getName()+" is saling tickets "+tickets--);
  }
 }
}

分析:上面程序实现了模拟铁路售票系统的要求。从上面程序中可以看出,我们只创建了一个资源对象 Resource(该对象中包含要发售的那100张票)。然后,我们在创建四个线程,每个线程去调用同一个
Resource对象中的run()方法,因此这四个线程访问的是同一个对象中的变量(tickets)的实例,从而实现了多线程访问同一资源的功能。

效果:



升华笔记2:实现Runnable接口相对于继承Thread类优势?

1.实现Runnable接口适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设计思想;

2.可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnanle接口的方式了。

3.实现Runnable接口有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个先的执行代码来自同一个类的实例时,即称他们共享相同的代码。多个线程可以操作相同的数据,于他们(线程)的代码无关。当共享访问相同的对象时,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。

三、守护(后台)进程与联合进程

1.后台进程

(1)概述:

在上面的售票系统的例子中,我们在main方法中创建并启动新的线程后,main方法便结束了,主线程也就随着结束了。但是,我们知道Java程序在运行的过程中只要还有一个前台线程在运行,整个Java程序(进程)没有随之结束,子线程的宿主进程便成为了一个空进程。当然,如果我们将该启动的新线程设置为后台进程,如果一个进程中只有该后台进程运行,这个进程便随着main方法的结束而结束。

设置某个进程为后台进程方法:

Thread thread=new Thread(runnable);

thread.setDaemon(true);                    //设置子进程为守护进程

thread.start();

(2)源码举例

//主线程
public class RunnableTest {
 public static void main(String[] args)
 {
  int i=10;
  TestRunnable runnable = new TestRunnable();	//创建一个类对象,该类继承于Runnable接口
  Thread thread=new Thread(runnable);	//创建一个带Runnable对象参数的线程
  thread.setDaemon(true);
  thread.start();	//启动该线程
  while((--i>0))
  {
   System.out.println("main thread is running.");
  }
 }
}
//子线程
class TestRunnable implements Runnable
{
 @Override
 public void run() {
  while(true)
  {
   System.out.println(Thread.currentThread().getName()+" is running.");
  }
 }

}

效果演示:

2.联合线程

所谓联合线程,就是当一个线程调用join()[如pp.join(),其中pp为线程对象方法后,把pp所对应的线程合并到调用pp.join()语句的线程中。

(1)Thread类的方法:

void join():合并线程

void join(long millis):线程合并millis毫秒后分离到合并前状态

void join(long millis,int nanos):线程合并millis毫秒nanos纳秒后分离到合并前状态

(2)源码举例

public class joinThead {
 public static void main(String[] args)
 {
  testThread t = new testThread();	//创建一个Runnable子类对象
  Thread thread=new Thread(t);	 //创建一个线程
  thread.start();  //启动线程
  int i=100;
  while(i>0)
  {
   if(i==50)
   {
    try {
     thread.join();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   System.out.println("main thread:"+i--);
  }
 }
}
class testThread implements Runnable
{
 private int i=100;
 public void run() {
  while(i>0)
  {
   i--;
   System.out.println(Thread.currentThread().getName()+": "+i );
  }
 }
}

效果分析:

经观察可知,当主线程的i递减=50时,子线程与主线程合并,此时只有子线程中的i在计算,直到子线程run方法代码运行完全两个线程再分离。最后,主线程继续执行后面的代码。

参考:http://docs.oracle.com/javase/8/docs/api/index.html

时间: 2024-10-25 23:42:02

Java笔记五.多线程的相关文章

java笔记--关于多线程如何查看JVM中运行的线程

查看JVM中的线程 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3890280.html "谢谢-- ThreadGroup(线程组)1.一个线程的集合,也可包含其他线程组2.线程组构成一棵树,除了初始化线程组外,每一个线程组都有一个父线程组3.允许线程访问有关自己的线程组的信息,但不能访问其父线程组或其他线程组的信息 常用方法:activeCount() 返回线程组中活动线程的估计数activeGroupCount() 返回线

java笔记--关于多线程状态的理解和应用

关于多线程的状态 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3890266.html  "谢谢-- 线程共有6种状态:1.新建线程---使用new来新建一个线程2.运行线程---调用start()方法,线程处于运行或可运行状态3.线程阻塞---线程需要获得内置锁,当该锁被其他线程使用时,此线程处于阻塞状态4.线程等待---当线程等待其他线程通知调度表可以运行时,此时线程处于等待状态5.线程计时等待---当线程调用含有时间参数的

JAVA笔记五

JAVA笔记 选择排序 0 1 2 3 4 3 1 0 2 9 将下标0依次和其他下标对比选择出最小的元素,再将下标1依次和其他下标对比选出最小的元素依次循环 每一次参与比较的元素进行减少:a.length-1 For(int i = 0 ;i<a.length-1;i++){ Int temp; For(int j =i+1;j<a.length;j++){ If(a[i]>a[j]){ Temp=a[i]; A[i]=a[j]; A[j]=temp } } } 冒泡排序:相邻的两个元

Java笔记:多线程

一.意义 使用多线程的目的是为了提高CPU资源的利用效率.在单线程应用中程序必须等待当前任务的完成才能继续执行下一项任务,CPU在等待的时间内就闲置了,多线程的使用可减少闲置时间. 二.主线程 当Java程序启动时,会立即开始运行主线程.其他所有的线程都是从主线程产生的,主线程必须是最后才结束执行的线程,因为它需要执行各种关闭动作.可以通过currentThread静态方法获取主线程的引用. class Solution { public static void main(String[] ar

JAVA笔记14__多线程共享数据(同步)/ 线程死锁 /

/** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两种方法: * 1.同步代码块 * synchronized(要同步的对象){ 要同步的操作 } * 2.同步方法 * public synchronized void method(){ 要同步的操作 } */ public class Main { public static void main(

JAVA笔记:多线程的理解及应用(一)

进程与线程 进程是程序的一次动态执行过程,它经历了从代码加载.执行.执行结束的一个完整过程,这个过程也是整个进程的生命周期. 多线程是实现并发机制的一种有效手段.进程和线程一样,都是实现并发机制的基本单位. 传统的单核CPU在同一个时间段可以有多个程序在执行,但是只能有一个程序在某一时间点运行,所有的程序都要抢占CPU资源. 多核CPU下程序会并发执行. Java中多线程的实现 Java中要实现多线程可以通过以下两种方式: 1.继承Thread类 2.实现Runnable接口 1.继承Threa

Java笔记之多线程

/* 多线程 进程:进程就是正在进行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元 线程:线程是进程中的内容或者说是进程中的一个独立的控制单元,线程控制者进程的执行,每一个进程中至少都会有一个线程 Java虚拟机启动的时候会有一个进程java.exe该进程中至少有一个线程在负责java程序的执行,而且这个线程运行的代码 存在于main方法中 多线程存在的意义:提高了程序的运行效率 */ class ThreadMainDemo1 extends Thread 

疯狂java笔记(五) - 系统交互、System、Runtime、Date类

一.程序与用户交互(Java的入口方法-main方法): 运行Java程序时,都必须提供一个main方法入口:public static void main(String[] args){} public:因为main方法里边可能包含同一包内或其他类的方法,为了保证能够正常执行该方法所以只能用该方法; static:调用主方法的时候不会先创建该主类的对象,而是直接通过该类来调用主方法的,所以使用static修饰; String[]:谁调用方法谁就为这个形参赋值,默认长度为0的数组 运行时:jav

JAVA笔记:多线程的理解及应用(二)

Java中的主方法其实也是一个线程,就叫做主线程. 问:既然主方法是以线程的形式出现的,那么Java中至少有多少个线程呢? 答案:至少有两个线程.每次启动Java的时候其实都会启动JVM,则其中的垃圾回收机制也算是一个线程,则一共有两个线程,主线程和GC. 判断线程是否启动可以使用.isAlive方法,返回的是布尔值. 线程的强制运行 在线程的操作中,可以使用join()方法让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等该线程运行完毕才能执行. 线程的休眠 程序中可以实现线程短暂