Java-并发编程基础--多线程用法

1.简单认识线程和进程

进程是指计算机上的一次执行活动,当运行一个程序时,就会启动一个进程。在多任务系统中,每个独立执行的程序称为一个进程。

线程是进程的一个实体,一个进程可以包含多个线程。和进程相比,线程占用的资源少,所以线程基本上可以认为是轻量级的进程。

2.为什么要使用线程

使用线程是为了最大限度的利用CPU资源,提高系统的效率,且看下面分析。

3.线程和进程的比较

  1. 进程是在操作系统上运行的,有独立的地址空间。进程之间的切换需要花费一定的时间和资源。而线程运行在进程内部,一个进程可以包含多个线程,线程之间的切换不会引起进程的切换。所以提高了系统的并发性能
  2. 操作系统中,进程拥有独立的资源,互不干扰。所以进程之间的通信是很麻烦,很复杂的。线程运行在进程内部,多个线程可以共享这个进程的所有资源,所以多线程之间实现通信是比较容易的
  3. 创建线程时不需要分配内存。它使用的是所属进程的资源。切换线程时,只需要保存少量的寄存器的内容。线程所消耗的系统资源远远小于进程消耗的资源

4.线程的生命周期

线程生命周期看看这张经典的图就明白了。

1.新建状态 (New)

当一个线程对象被声明并创建时,线程就处于新建状态。例如: Thread t = new MyThread(),对象创建了,就处于了新建状态。在新建状态,线程并未分配到CPU资源,可以执行start()和stop()方法。

2.可运行状态(Runnable)

新建状态的的线程调用start()方法时,线程将进入线程队列等待CPU服务。该状态的线程位于可运行线程池中,等待获取CPU资源。(线程执行start()方法并不是直接就运行了,而是在线程池中等待获取CPU)

3.运行状态(Running)

在线程池中的线程获取到CPU资源以后,才可以执行,变成运行状态。Runnable状态是进入Running状态的唯一接口。也就是说线程想要进入运行状态,必须先进入可运行状态。

4.阻塞状态(Blocked)

正在执行的线程由于某种原因放弃了CPU的使用权,该线程就进入了阻塞状态。处于阻塞状态的线程不能立即进入可运行状态等待再次运行。只有阻塞的原因消失以后,才有可能再次获得CPU的使用权。

  1. 等待阻塞:线程运行wait()时,只有满足某种条件。此时,Java虚拟机才会把线程放入等待池中。
  2. 同步阻塞:如果线程获取锁失败时,Java虚拟机会把该线程放入锁池中。
  3. 其他阻塞:通过调用线程的sleep(),join()或发出I/O请求时,线程进入阻塞状态。当sleep()超时,join()等待线程完成或超时,I/O处理完毕的情况下。线程进入就绪状态。

5.线程结束状态(Dead)

线程执行完run()方法,或者调用stop()退出run()方法。或者抛出一个未捕获的异常时,该线程的生命周期就结束了。


5.实现多线程的方法

5.1 继承Thread类

继承Thread类必须重写run()方法,而且必须调用Thread类的start()方法启动线程。

package com.huawei.galaxy.thread;

public class ThreadTest extends Thread {

    String threadName;

    ThreadTest(String name) {
	this.threadName = name;
    }

    public void run() {
	for (int i = 1; i <= 10; i++) {
	    System.out.println(threadName + " (" + i + ")");
	}
    }

    public static void main(String[] args) {
	
	new ThreadTest("Thread-1").start();
	new ThreadTest("Thread-2").start();
	new ThreadTest("Thread-3").start();

    }
}

5.2 实现Runnable接口

实际上Thread类也实现了Runnable接口,Runnable接口提供了一个public void run()方法,使用Runnable接口也需要实现run()方法。也需要创建Thread对象,通过这个对象调用start(),最终调用run()方法来实现多线程。

使用Runnable接口实现创建多线程需要注意一下:

1)在创建类时实现Runnable接口,并重写run()方法。

2)由于Runnable接口,不能直接创建爱你所需类的对象并运行它,必须从Thread类的一个实例内部运行它。

package com.huawei.galaxy.thread;

public class RunnableTest implements Runnable{

    String threadName;
    
    RunnableTest(String name)
    {
	this.threadName = name;
    }
    @Override
    public void run() {
	for(int i = 0;i < 10;i++)
	{
	    System.out.println(threadName + "(" + i + ")");
	}
    }

    public static void main(String[] args) {
	// 不能通过实现了Runnable接口的类创建线程,
	// 实现了Runnable接口的线程必须运行在Thread对象内部。
	Thread thread1 = new Thread(new RunnableTest("Thread-1"));
	Thread thread2 = new Thread(new RunnableTest("Thread-2"));
	Thread thread3 = new Thread(new RunnableTest("Thread-3"));
	thread1.start();
	thread2.start();
	thread3.start();
    }
}

最好还是用Runnable接口来实现线程。 因为Java是单继承的,使用Runnable接口可以避免单继承带来的局限。

6.线程的调度方法

线程调度方法有很多,自行查询API文档。主要讨论几个

6.1获取当前正在执行的线程

Thread类的静态方法,currentThread()方法可以获取当前正在执行的线程。

package com.huawei.galaxy.thread;

public class CurrentThread implements Runnable{

    @Override
    public void run() {
	System.out.println(Thread.currentThread().getName());
	System.out.println(Thread.currentThread());
    }

    public static void main(String[] args) {
	Thread thread1 = new Thread(new CurrentThread());
	Thread thread2 = new Thread(new CurrentThread());
	thread1.start();
	thread2.start();
    }
}

执行结果:

Thread-0
Thread-1
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]

 

 6.2等待线程终止

join()方法可以暂停当前的线程,知道调用join方法的线程执行完成,在执行当前线程。

package com.huawei.galaxy.thread;

public class JoinTest implements Runnable {

    public void run() {
	for (int i = 0; i < 5; i++) {
	    System.out
	    .println(Thread.currentThread().getName() + "(" + i + ")");
	    try {
		Thread.sleep(1000);
	    } catch (InterruptedException e) {
	    }
	
	}
    }

    public static void main(String[] args) {
	Thread t0 = new Thread(new JoinTest());
	Thread t1 = new Thread(new JoinTest());
	System.out.println("0-" + t0.isAlive());
	System.out.println("0-" + t1.isAlive());
	t0.start();
	t1.start();
	System.out.println("1-" + t0.isAlive());
	System.out.println("1-" + t1.isAlive());
	try {
	    t0.join();
	    t1.join();
	} catch (InterruptedException e) {
	}

	System.out.println("2-" + t0.isAlive());
	System.out.println("2-" + t1.isAlive());
	for(int i = 0; i< 5;i++)
	{
	    System.out.println(Thread.currentThread().getName());
	}
    }
}

运行结果:

0-false
0-false
1-true
1-true
Thread-0(0)
Thread-1(0)
Thread-0(1)
Thread-1(1)
Thread-0(2)
Thread-1(2)
Thread-1(3)
Thread-0(3)
Thread-1(4)
Thread-0(4)
2-false
2-false
main
main
main
main
main

 

如果不写Join的运行结果如下:

0-false
0-false
1-true
1-true
2-true
2-true
main
main
main
main
main
Thread-0(0)
Thread-1(0)
Thread-0(1)
Thread-1(1)
Thread-0(2)
Thread-1(2)
Thread-0(3)
Thread-1(3)
Thread-1(4)
Thread-0(4)

 

 6.3暂停正在执行的线程的方法

yield()方法会暂停当前正在执行的方法,让别的线程执行。比如线程A调用了yield()方法,作用就是线程A暂时不执行,让出CPU控制权,让线程B执行。

package com.huawei.galaxy.thread;

public class YieldThreadTest implements Runnable{

    @Override
    public void run() {
	for(int i = 0;i<5;i++)
	{
	    System.out.println(Thread.currentThread().getName() + " " + i);
	    Thread.yield();
	}
    }

    public static void main(String[] args) {
	YieldThreadTest yt = new YieldThreadTest();
	Thread t1 = new Thread(yt);
	Thread t2 = new Thread(yt);
	Thread t3 = new Thread(yt);
	t1.start();
	t2.start();
	t3.start();
    }
}

执行结果:

Thread-0 0
Thread-1 0
Thread-2 0
Thread-1 1
Thread-2 1
Thread-1 2
Thread-2 2
Thread-1 3
Thread-2 3
Thread-1 4
Thread-0 1
Thread-2 4
Thread-0 2
Thread-0 3
Thread-0 4

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值