Java并发编程,是Java的高级开发部分,平时项目很少用到,主要原因还是不熟悉,从今天开始整体学习研究下,后面会有一个系列的学习,也为以后在项目中经常使用打下基础。首先来回顾下Java最基本的多线程开发,就是java.lang.Thread类。
以下是本文包含的知识点:
一、线程的基本概念
二、线程的创建和启动
三、线程的状态控制
四、线程的同步
五、生产者消费
下面开始本文的内容:
一、线程的基本概念
线程(英语:thread)是操作系统能夠進行運算调度的最小單位。 它被包含在进程之中,是进程中的實際運作單位。 一条线程指的是进程中一个单一顺序的控制流,一個进程中可以並行多個线程,每条线程并行执行不同的任务。(来自维基百科)
简单来说:线程是一个程序内部的顺序控制流。
线程和进程的区别:
1.每个进程有独立的代码和数据空间,进程间的切换会有较大开销。
2.在一个操作系统中可以运行多个进程。
3.一个进程中可以并行运行多个线程。
4.一个进程中的多个线程共享这个进程中的资源,如代码,数据空间。
还可以参考阮一峰的:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
二、Java线程的创建和启动
当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的
main
方法)。在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆。
只要有一个非守护线程还在运行,守护线程就不能结束,当所有非守护线程都运行结束,守护线程也随着JVM一同结束。最典型的守护线程是GC(垃圾回收器)。
JVM启动时会有一个主方法(public static void main(String []args))所定义的线程。也叫主线程
Java通过创建Thread实例来创建新的线程,
每个线程都是通过某个特定的Thread对象的run()方法来完成它的操作,run()方法称为线程体。
通过调用Thread类的start()方法来启动一个线程。
通过JDK6的API文档http://tool.oschina.net/apidocs/apidoc?api=jdk-zh,我们看到有两种创建线程的方式:
一种方法是将类声明为
Thread
的子类, 该子类应重写 Thread
类的 run
方法:class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
然后,下列代码会创建并启动一个线程:
PrimeThread p = new PrimeThread(143); p.start();
另一种方法是声明实现 Runnable
接口的类。该类然后实现 run
方法:
class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
然后,下列代码会创建并启动一个线程:
PrimeRun p = new PrimeRun(143); new Thread(p).start();
每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。
三、线程的状态控制
线程控制的基本方法有:
isAlive():判断线程是否还“活”着,即线程是否还未终止
Thread.sleep():将当前线程睡眠指定的毫秒数
join():调用某线程的该方法,将当前线程与该线程合并,即等待该线程结束,再恢复当前线程的运行。
yield():让出CPU,当前线程进入就绪队列等待调度。
wait():当前线程进入对象的wait pool。
notify()/notifyAll():唤醒对象的wait pool中的一个/所有等待线程。
Thread.currentThrad():获得当前线程的引用。
线程的优先级:
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。
线程调度器按线程的优先级来决定应调度哪个线程来执行。
通过阅读源码,看到线程优先级用数字表示,从1到10,默认为5。
通过下列方法来获取或设置某个线程的优先级:
getPriority():获得线程的优先级数
setPriority():设置线程的优先级数
四、线程同步:
先来看下面一段代码:
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 void add(String name) { num++; System. out.println(name + ", 你是第" + num + "个使用timer的线程" ); } }我们期望的结果是:
t1, 你是第1个使用timer的线程
t2, 你是第2个使用timer的线程
然而,实际执行的结果却是:
t1, 你是第2个使用timer的线程
t2, 你是第2个使用timer的线程
为什么会出现意想不到的情况呢,我们按实际结果的情况来分析下:
首先,t1先执行了,将num++变成了1。
此时,t2开始执行(注意这里t1并未执行完),将num++变成了2 。
然后,t1接着执行,打印System.out输出,结果为 t1, 你是第2个使用timer的线程。
最后,t2接着执行,打印System.out输出,结果为 t2, 你是第2个使用timer的线程。
按上面的分析,我们知道出现这种情况的原因是t1,t2在执行线程体访问同一个对象的过程中被打断了。
那么如何不被打断呢,这就要用到线程同步。
在Java中引入对象互斥锁的概念,保证共享数据操作的完整性。
每个对象都对应于一个称为“互斥锁”的标记,这个标记保证在任一时刻,只能有一个线程访问该对象。
关键字synchronized来表示对象的互斥锁,当某个对象被synchronized修饰时,表示该对象在任一时刻只能由一个线程访问。
synchronized的使用方法,如对上例的修改:
1.作用于代码块上:
synchronize(this){ num++; System. out.println(name + ", 你是第" + num + "个使用timer的线程" ); }2.放在方法声明中,表示整个方法为同步方法:
public synchronized void add(String name) { num++; System. out.println(name + ", 你是第" + num + "个使用timer的线程" ); }
五、生产者消费者
/** * 生产者消费者 * 举例:生产窝头,消费窝头 * @author Yuwl */ public class TestProducerConsumer { public static void main(String[] args) { SyncStack ss = new SyncStack(); Producer p = new Producer(ss); Consumer c = new Consumer(ss); new Thread(p).start(); new Thread(c).start(); } } /** * 窝头 */ class WoTou { int id; WoTou(int id){ this. id = id; } public String toString() { return "WoTou id=" + id ; } } /** * 篮子-栈的实现[先进后出] */ class SyncStack { int index = 0; WoTou []arrWt = new WoTou[6]; public synchronized void push(WoTou wt){ while( index == arrWt. length){ //如果篮子满了 try { this.wait(); //让当前线程进入当前对象的wait pool } catch (InterruptedException e) { e.printStackTrace(); } } this.notifyAll(); //唤醒其它正在等待的线程 arrWt[ index] = wt; index++; } public synchronized WoTou take(){ while( index == 0){//如果篮子空了 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.notifyAll(); index--; return arrWt[ index]; } } /** * 生产者 */ class Producer implements Runnable { SyncStack ss; Producer(SyncStack ss){ this. ss = ss; } public void run(){ for( int i=0; i<20; i++){ WoTou wt = new WoTou(i); ss.push(wt); System. out.println( "生产了 "+wt); try { Thread. sleep((long)(Math.random()*200)); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 消费者 */ class Consumer implements Runnable { SyncStack ss; public Consumer(SyncStack ss) { this. ss = ss; } public void run(){ for( int i=0; i<20; i++){ WoTou wt = ss.take(); System. out.println( "消费了 "+wt); try { Thread. sleep((long)(Math.random()*1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }其中一次的运行结果:
生产了 WoTou id=0 消费了 WoTou id=0 生产了 WoTou id=1 生产了 WoTou id=2 消费了 WoTou id=2 生产了 WoTou id=3 生产了 WoTou id=4 生产了 WoTou id=5 生产了 WoTou id=6 生产了 WoTou id=7 消费了 WoTou id=7 生产了 WoTou id=8 消费了 WoTou id=8 生产了 WoTou id=9 生产了 WoTou id=10 消费了 WoTou id=9 消费了 WoTou id=10 生产了 WoTou id=11 生产了 WoTou id=12 消费了 WoTou id=11 生产了 WoTou id=13 消费了 WoTou id=12 消费了 WoTou id=13 生产了 WoTou id=14 消费了 WoTou id=14 生产了 WoTou id=15 生产了 WoTou id=16 消费了 WoTou id=15 消费了 WoTou id=16 生产了 WoTou id=17 消费了 WoTou id=17 生产了 WoTou id=18 消费了 WoTou id=18 生产了 WoTou id=19 消费了 WoTou id=19 消费了 WoTou id=6 消费了 WoTou id=5 消费了 WoTou id=4 消费了 WoTou id=3 消费了 WoTou id=1
参考:
JDK6中文API
尚学堂马士兵老师J2SE视频
相关推荐
《Java并发编程:设计原则与模式(第二版)》是一本深入探讨Java多线程编程技术的权威著作。这本书详细阐述了在Java平台中进行高效并发处理的关键概念、设计原则和实用模式。以下是对该书内容的一些核心知识点的概述...
《Java并发编程:设计原则与模式》是一本深入探讨Java多线程编程的书籍,它涵盖了并发编程中的关键概念、原则和模式。在Java中,并发处理是优化应用程序性能、提高资源利用率的重要手段,尤其在现代多核处理器的环境...
这些API是Java并发编程的核心,书中会详细解析它们的使用方法和应用场景。 3. **线程安全**:线程安全是并发编程中的重要主题,书中会探讨各种线程安全的实现策略,如使用`synchronized`关键字、`volatile`变量、`...
《Java并发编程:设计原则与模式(第二版)》是一本深入探讨Java平台上的多线程和并发编程的权威著作。这本书旨在帮助开发者理解和掌握如何有效地编写可扩展且高效的并发程序。以下是书中涵盖的一些关键知识点: 1....
读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位的详细内容,例如限制和同步、...
Java并发编程中的线程池是提高系统效率的关键工具,它解决了频繁创建和销毁线程的问题。线程池通过复用已存在的线程来处理任务,从而避免了每次任务执行完毕后销毁线程的开销。在Java中,线程池的核心实现是`java....
《Java并发编程 设计原则与模式 第二版》是一本深受程序员喜爱的经典书籍,由Addison Wesley出版。这本书深入探讨了Java平台上的多线程编程技术,为开发者提供了丰富的设计原则和模式,帮助他们理解和解决并发环境中...
本资料“Java并发编程:设计原则与模式”深入探讨了这些关键主题。 首先,我们需要理解Java并发编程的基础概念。Java中的并发是通过线程实现的,线程是程序执行的最小单位。Java提供了多种创建和管理线程的方法,如...
《Java并发编程:设计原则与模式(第二版)》是一本深入探讨Java多线程编程技术的权威著作。这本书详细阐述了如何在Java环境中高效、安全地进行并发编程,涵盖了多线程设计的关键原则和常见模式。对于Java开发者来说...
《Java并发编程:设计原则与模式》是一本深入探讨Java多线程编程的权威书籍,由Doug Lea撰写,第二版全面涵盖了Java并发处理的各个方面。这本书不仅提供了丰富的理论知识,还介绍了实战中的设计原则和模式,对于Java...
根据提供的信息,“Java 并发编程实战.pdf”这本书聚焦于Java并发编程的实践与应用,旨在帮助读者深入了解并掌握Java中的多线程技术及其在实际项目中的应用技巧。虽然部分内容未能提供具体章节或实例,但从标题及...
"Java并发编程与实践"文档深入剖析了这一主题,旨在帮助开发者理解和掌握如何在Java环境中有效地实现并发。 并发是指在单个执行单元(如CPU)中同时执行两个或更多任务的能力。在Java中,这主要通过线程来实现,...
《Java并发编程艺术》这本书深入探讨了Java平台上的并发编程技术。并发编程是现代多核处理器环境下提升软件性能的关键手段,而Java语言提供了丰富的工具和API来支持这一领域。本书旨在帮助开发者理解和掌握如何在...
《Java并发编程实战》是一本深入探讨Java平台并发编程的权威指南。这本书旨在帮助开发者理解和掌握在Java环境中创建高效、可扩展且可靠的多线程应用程序的关键技术和实践。它涵盖了从基本概念到高级主题的广泛内容,...
此外,Java并发编程还包括对并发容器的使用,如ArrayList、LinkedList、HashSet、HashMap等基础容器在并发环境下可能存在问题,Java提供了一些线程安全的容器,如Vector、HashTable以及java.util.concurrent包下的...
本文将深入探讨Java并发编程的设计原则与模式,旨在帮助开发者理解并有效地应用这些原则和模式。 一、并发编程的基础概念 并发是指两个或多个操作在同一时间间隔内执行,而不是严格意义上的同一时刻。在Java中,...
Java并发编程中的线程基础是理解多线程编程的关键,它涵盖了从线程的创建到管理,再到线程间通信的全过程。多线程编程在处理高性能和高响应性的应用程序时至关重要,因为它允许程序在单个进程中同时执行多个任务,...
《JAVA并发编程艺术》是Java开发者深入理解和掌握并发编程的一本重要著作,它涵盖了Java并发领域的核心概念和技术。这本书详细阐述了如何在多线程环境下有效地编写高效、可靠的代码,对于提升Java程序员的技能水平...
Java并发编程是软件开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。本资源"Java并发编程_设计原则和模式(CHM)"聚焦于Java语言在并发环境下的编程技巧、...