`
yuwenlin2008
  • 浏览: 124891 次
  • 性别: 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并发编程:设计原则与模式(第二版)

    读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位的详细内容,例如限制和同步、...

    java并发编程:线程基础

    本资源致力于向您介绍 Java 并发编程中的线程基础,涵盖了多线程编程的核心概念、线程的创建和管理,以及线程间通信的基本方法。通过深入学习,您将建立扎实的多线程编程基础,能够更好地理解和应用多线程编程。 多...

    Java 并发核心编程

    本文的主题是关于具有java语言风格的Thread、synchronized、volatile,以及J2SE5中新增的概念,如锁(Lock)、原子性(Atomics)、并发集合类、线程协作摘要、Executors。开发者通过这些基础的接口可以构建高并发、线程...

    java并发编程:Executor、Executors、ExecutorService.docx

    其方法签名为executor(Runnable command),该方法接收一个Runable实例,它用来执行一个任务,任务即一个实现了Runnable接口的类,一般来说,Runnable任务开辟在新线程中的使用方法为:new Thread(new RunnableTask())...

    java并发编程

    本书全面介绍了如何使用Java 2平台进行并发编程,较上一版新增和扩展的内容包括:, ·存储模型 ·取消 ·可移植的并行编程 ·实现并发控制的工具类, Java平台提供了一套广泛而功能强大的api,工具和技术。...

    Java并发编程---Thread类

    Java并发编程---Thread类!!

    精通Java并发编程(第2版)【试读】

    然后介绍了Thread类和Runnable接口,它们是Java并发API的重要组成部分。接着讨论了如何利用Java并发API的各种元素(从基本技巧到高级技巧),以及如何在强大的真实并发应用程序中实现它们。最后详细介绍了测试并发...

    Java 7并发编程实战手册

    java7在并发编程方面,带来了很多令人激动的新功能,这将使你的应用程序具备更好的并行任务性能。 《Java 7并发编程实战手册》是Java 7并发编程的实战指南,介绍了Java 7并发API中大部分重要而有用的机制。全书分为9...

    Java并发编程实践2

    这本书名为《Java并发编程实践》有些抹杀了它的价值,其中并非只讲述了Java的多线程设施,对一般的并发编程的rationale也有相当透彻的阐述。之前看过各种线程库,pThread, Boost Thread, Java Thread, Qt Thread,...

    java并发编程实践

    这本书名为《Java并发编程实践》有些抹杀了它的价值,其中并非只讲述了Java的多线程设施,对一般的并发编程的rationale也有相当透彻的阐述。之前看过各种线程库,pThread, Boost Thread, Java Thread, Qt Thread,...

    汪文君高并发编程实战视频资源下载.txt

    │ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...

    Java并发编程(学习笔记).xmind

    Java并发编程 背景介绍 并发历史 必要性 进程 资源分配的最小单位 线程 CPU调度的最小单位 线程的优势 (1)如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率 ...

    java技能总结.docx

    掌握Java的高级特性:掌握Java的反射、泛型、注解、并发编程等高级特性,以及Java集合框架和并发包的使用。 掌握Java Web开发:掌握Java Web开发的相关技术,如Servlet、JSP、Spring、Hibernate等,能够开发基于Web...

    Java高并发编程详解.md

    有关java高并发知识总结:三种线程创建方式 深入理解Thread构造函数 Thread API #### CAS缺陷 ##### 循环时间长开销大,自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。 ##### 只能保证一个共享变量...

    Java并发编程实战(中文版)

    Java并发编程实战(中文版)

    Java并发编程实践

    第一章 Java 并发编程实践基础..............................................................1 1.1 进程与线程.................................................................................................

    Java高并发编程详解:多线程与架构设计 (Java核心技术系列)

    第三部分详细、深入地介绍volatile关键字的语义,volatile关键字在Java中非常重要,可以说它奠定了Java核心并发包的高效运行,在这一部分中,我们通过实例展示了如何使用volatile关键字以及非常详细地介绍了Java内存...

    java并发编程实战 pdf

    学习Java其实应该上升到如何学习程序设计这种境界,其实学习程序设计又是接受一种编程思想。每一种语言的程序设计思想大同小异,只是一些由语言特性的而带来的细微差别,比如Java中的Interface,你几乎在以前的学习...

    java并发编程的艺术

    并发编程艺术

    java并发编程源码分析-javaThread:java并发编程实战手册源码分析

    java并发编程源码分析

Global site tag (gtag.js) - Google Analytics