`
yuwenlin2008
  • 浏览: 128726 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java并发编程:Thread类的使用

阅读更多
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视频
 
  • 大小: 76.3 KB
0
1
分享到:
评论

相关推荐

    Java并发编程_设计原则和模式(CHM)

    Java并发编程是软件开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。本资源"Java并发编程_设计原则和模式(CHM)"聚焦于Java语言在并发环境下的编程技巧、...

    Java并发编程的设计原则与模式

    本文将深入探讨Java并发编程的设计原则与模式,旨在帮助开发者理解并有效地应用这些原则和模式。 一、并发编程的基础概念 并发是指两个或多个操作在同一时间间隔内执行,而不是严格意义上的同一时刻。在Java中,...

    Java 并发编程:设计原则与模式

    本资料“Java并发编程:设计原则与模式”深入探讨了这些关键主题。 首先,我们需要理解Java并发编程的基础概念。Java中的并发是通过线程实现的,线程是程序执行的最小单位。Java提供了多种创建和管理线程的方法,如...

    java并发编程艺术

    《Java并发编程艺术》这本书深入探讨了Java平台上的并发编程技术。并发编程是现代多核处理器环境下提升软件性能的关键手段,而Java语言提供了丰富的工具和API来支持这一领域。本书旨在帮助开发者理解和掌握如何在...

    Java 并发编程实战.pdf

    根据提供的信息,“Java 并发编程实战.pdf”这本书聚焦于Java并发编程的实践与应用,旨在帮助读者深入了解并掌握Java中的多线程技术及其在实际项目中的应用技巧。虽然部分内容未能提供具体章节或实例,但从标题及...

    《java 并发编程实战高清PDF版》

    《Java并发编程实战》是一本深入探讨Java平台并发编程的权威指南。这本书旨在帮助开发者理解和掌握在Java环境中创建高效、可扩展且可靠的多线程应用程序的关键技术和实践。它涵盖了从基本概念到高级主题的广泛内容,...

    java并发编程与实践

    "Java并发编程与实践"文档深入剖析了这一主题,旨在帮助开发者理解和掌握如何在Java环境中有效地实现并发。 并发是指在单个执行单元(如CPU)中同时执行两个或更多任务的能力。在Java中,这主要通过线程来实现,...

    java并发编程内部分享PPT

    此外,Java并发编程还包括对并发容器的使用,如ArrayList、LinkedList、HashSet、HashMap等基础容器在并发环境下可能存在问题,Java提供了一些线程安全的容器,如Vector、HashTable以及java.util.concurrent包下的...

    JAVA并发编程艺术pdf版

    《JAVA并发编程艺术》是Java开发者深入理解和掌握并发编程的一本重要著作,它涵盖了Java并发领域的核心概念和技术。这本书详细阐述了如何在多线程环境下有效地编写高效、可靠的代码,对于提升Java程序员的技能水平...

    Java并发编程实践高清pdf及源码

    《Java并发编程实践》是一本深入探讨Java多线程编程的经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和David Holmes等专家共同编写。这本书全面介绍了Java平台上的并发编程技术,是Java开发...

    java并发编程:线程基础

    Java并发编程中的线程基础是理解多线程编程的关键,它涵盖了从线程的创建到管理,再到线程间通信的全过程。多线程编程在处理高性能和高响应性的应用程序时至关重要,因为它允许程序在单个进程中同时执行多个任务,...

    java并发编程书籍

    Java并发编程是软件开发中的一个关键领域,尤其是在大型企业级应用和分布式系统中。通过学习相关的书籍,开发者可以深入理解如何有效地设计和实现高效的多线程应用程序,避免并发问题,如竞态条件、死锁、活锁等。...

    (PDF带目录)《Java 并发编程实战》,java并发实战,并发

    《Java 并发编程实战》是一本专注于Java并发编程的权威指南,对于任何希望深入了解Java多线程和并发控制机制的开发者来说,都是不可或缺的参考资料。这本书深入浅出地介绍了如何在Java环境中有效地管理和控制并发...

    JAVA并发编程实践.pdf+高清版+目录 书籍源码

    《JAVA并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。它涵盖了Java并发的核心概念、工具和最佳实践,旨在帮助读者在多线程环境下编写高效、安全的代码。 并发编程是现代软件开发中的关键技能,...

    《java并发编程的核心方法和框架》

    Java并发编程是Java开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。《java并发编程的核心方法和框架》这本书旨在深入探讨这一主题,帮助开发者掌握Java...

    java并发编程78讲.pdf

    综上所述,尽管Java并发编程中创建线程的方法看似多种多样,但从根本上来说,都离不开实现`Runnable`接口和继承`Thread`类这两种基本方式。掌握这些基础知识对于深入理解和应用Java并发编程至关重要。

    java并发编程

    Java并发编程是Java开发者必须掌握的关键技能之一,它涉及到如何在多线程环境中高效、安全地执行程序。并发编程能够充分利用多核处理器的计算能力,提高应用程序的响应速度和整体性能。《Java编程并发实战》这本书是...

    13-Java并发编程学习宝典.zip

    Java并发编程是软件开发中的重要领域,特别是在大型系统和高并发场景中不可或缺。"13-Java并发编程学习宝典.zip" 包含了一系列关于Java并发编程的学习资源,旨在帮助开发者掌握多线程编程的核心技术和最佳实践。以下...

Global site tag (gtag.js) - Google Analytics