`

Java.lang.Thread 和 Java.lang.ThreadGroup

阅读更多
多线程
线程:是指进程中的一个执行流程。
线程与进程的区别:每个进程都需要操作系统为其分配独立的内存地址空间,而同一进程中的所有线程在同一块地址空间中工作,这些线程可以共享同一块内存和系统资源。

如何创建一个线程?

创建线程有两种方式,如下:
1、 扩展java.lang.Thread类
2、 实现Runnable接口
Thread类代表线程类,它的两个最主要的方法是:
run()——包含线程运行时所执行的代码
Start()——用于启动线程

一个线程只能被启动一次。第二次启动时将会抛出java.lang.IllegalThreadExcetpion异常

线程间状态的转换

新建状态:用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存
就绪状态:当一个线程创建了以后,其他的线程调用了它的start()方法,该线程就进入了就绪状态。处于这个状态的线程位于可运行池中,等待获得CPU的使用权
运行状态:处于这个状态的线程占用CPU,执行程序的代码
阻塞状态:当线程处于阻塞状态时,java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到运行状态。
阻塞状态分为三种情况:
1、 位于对象等待池中的阻塞状态:当线程运行时,如果执行了某个对象的wait()方法,java虚拟机就回把线程放到这个对象的等待池中
2、 位于对象锁中的阻塞状态,当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他的线程占用,JVM就会把这个线程放到这个对象的琐池中。
3、 其它的阻塞状态:当前线程执行了sleep()方法,或者调用了其它线程的join()方法,或者发出了I/O请求时,就会进入这个状态中。

死亡状态:当线程退出了run()方法,就进入了死亡状态,该线程结束了生命周期。
           或者正常退出
           或者遇到异常退出
           Thread类的isAlive()方法判断一个线程是否活着,当线程处于死亡状态或者新建状态时,该方法返回false,在其余的状态下,该方法返回true.

线程调度
线程调度模型:分时调度模型和抢占式调度模型
JVM采用抢占式调度模型。
所谓的多线程的并发运行,其实是指宏观上看,各个线程轮流获得CPU的使用权,分别执行各自的任务。
(线程的调度不是跨平台,它不仅取决于java虚拟机,它还依赖于操作系统)

如果希望明确地让一个线程给另外一个线程运行的机会,可以采取以下的办法之一
1、 调整各个线程的优先级
2、 让处于运行状态的线程调用Thread.sleep()方法
3、 让处于运行状态的线程调用Thread.yield()方法
4、 让处于运行状态的线程调用另一个线程的join()方法

调整各个线程的优先级
Thread类的setPriority(int)和getPriority()方法分别用来设置优先级和读取优先级。
如果希望程序能够移值到各个操作系统中,应该确保在设置线程的优先级时,只使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY这3个优先级。

线程睡眠:当线程在运行中执行了sleep()方法时,它就会放弃CPU,转到阻塞状态。
线程让步:当线程在运行中执行了Thread类的yield()静态方法时,如果此时具有相同优先级的其它线程处于就绪状态,那么yield()方法将把当前运行的线程放到运行池中并使另一个线程运行。如果没有相同优先级的可运行线程,则yield()方法什么也不做。
Sleep()方法和yield()方法都是Thread类的静态方法,都会使当前处于运行状态的线程放弃CPU,把运行机会让给别的线程,两者的区别在于:
         1、sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。
2、当线程执行了sleep(long millis)方法后,将转到阻塞状态,参数millis指定睡眠时间;当线程执行了yield()方法后,将转到就绪状态。
          3、sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明抛出任何异常
          4、sleep()方法比yield()方法具有更好的移植性

等待其它线程的结束:join()
          当前运行的线程可以调用另一个线程的 join()方法,当前运行的线程将转到阻塞状态,直到另一个线程运行结束,它才恢复运行。

定时器Timer:在JDK的java.util包中提供了一个实用类Timer, 它能够定时执行特定的任务。

线程的同步
原子操作:根据Java规范,对于基本类型的赋值或者返回值操作,是原子操作。但这里的基本数据类型不包括long和double, 因为JVM看到的基本存储单位是32位,而long 和double都要用64位来表示。所以无法在一个时钟周期内完成。

自增操作(++)不是原子操作,因为它涉及到一次读和一次写。

原子操作:由一组相关的操作完成,这些操作可能会操纵与其它的线程共享的资源,为了保证得到正确的运算结果,一个线程在执行原子操作其间,应该采取其他的措施使得其他的线程不能操纵共享资源。

同步代码块:为了保证每个线程能够正常执行原子操作,Java引入了同步机制,具体的做法是在代表原子操作的程序代码前加上synchronized标记,这样的代码被称为同步代码块。

同步锁:每个JAVA对象都有且只有一个同步锁,在任何时刻,最多只允许一个线程拥有这把锁。

当一个线程试图访问带有synchronized(this)标记的代码块时,必须获得 this关键字引用的对象的锁,在以下的两种情况下,本线程有着不同的命运。
1、 假如这个锁已经被其它的线程占用,JVM就会把这个线程放到本对象的锁池中。本线程进入阻塞状态。锁池中可能有很多的线程,等到其他的线程释放了锁,JVM就会从锁池中随机取出一个线程,使这个线程拥有锁,并且转到就绪状态。
2、 假如这个锁没有被其他线程占用,本线程会获得这把锁,开始执行同步代码块。
(一般情况下在执行同步代码块时不会释放同步锁,但也有特殊情况会释放对象锁
如在执行同步代码块时,遇到异常而导致线程终止,锁会被释放;在执行代码块时,执行了锁所属对象的wait()方法,这个线程会释放对象锁,进入对象的等待池中)

线程同步的特征:
1、 如果一个同步代码块和非同步代码块同时操作共享资源,仍然会造成对共享资源的竞争。因为当一个线程执行一个对象的同步代码块时,其他的线程仍然可以执行对象的非同步代码块。(所谓的线程之间保持同步,是指不同的线程在执行同一个对象的同步代码块时,因为要获得对象的同步锁而互相牵制)
2、 每个对象都有唯一的同步锁
3、 在静态方法前面可以使用synchronized修饰符。
4、 当一个线程开始执行同步代码块时,并不意味着必须以不间断的方式运行,进入同步代码块的线程可以执行Thread.sleep()或者执行Thread.yield()方法,此时它并不释放对象锁,只是把运行的机会让给其他的线程。
5、 Synchronized声明不会被继承,如果一个用synchronized修饰的方法被子类覆盖,那么子类中这个方法不在保持同步,除非用synchronized修饰。

线程安全的类:
1、 这个类的对象可以同时被多个线程安全的访问。
2、 每个线程都能正常的执行原子操作,得到正确的结果。
3、 在每个线程的原子操作都完成后,对象处于逻辑上合理的状态。

释放对象的锁:
1、 执行完同步代码块就会释放对象的锁
2、 在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放
3、 在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程会释放对象锁,进入对象的等待池。

死锁
当一个线程等待由另一个线程持有的锁,而后者正在等待已被第一个线程持有的锁时,就会发生死锁。JVM不监测也不试图避免这种情况,因此保证不发生死锁就成了程序员的责任。

如何避免死锁
一个通用的经验法则是:当几个线程都要访问共享资源A、B、C 时,保证每个线程都按照同样的顺序去访问他们。

线程通信
Java.lang.Object类中提供了两个用于线程通信的方法
1、 wait():执行了该方法的线程释放对象的锁,JVM会把该线程放到对象的等待池中。该线程等待其它线程唤醒
2、 notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程,JVM从对象的等待池中随机选择一个线程,把它转到对象的锁池中。
(以上内容转载至:http://hi.baidu.com/%CE%E2_%F0%A9/blog/item/be1bb60fe3c5a6c17bcbe119.html 内容很不错。不过完全理解这些内容,需要些时间)

1. Thread 中的死锁例子。
重点理解包括:
  • 主线程和新生成的线程是如何工作的,如何分配资源。
  • synchronize锁的使用。这是java线程中非常重要的部分。


package com.java.lang.thread;

/**
 * 锁住了自己,去调用别的锁,发现互相锁住了对方。
 * @author yuahan
 *
 */
class A {
	synchronized void foo(B b) {
		String name = Thread.currentThread().getName();
		System.out.println(name + " entered A.foo(B b)");

		System.out.println(name + " trying to call B.last()");
		b.last();
	}

	synchronized void last() {
		System.out.println("Inside A.last");
	}
}

class B {
	synchronized void bar(A a) {
		String name = Thread.currentThread().getName();
		System.out.println(name + " entered B.bar(A a)");
		
		System.out.println(name + " trying to call A.last()");
		a.last();
	}

	synchronized void last() {
		System.out.println("Inside B.last");
	}
}

public class Deadlock implements Runnable {
	A a = new A();
	B b = new B();

	Deadlock() {
		Thread t = new Thread(this, "RacingThread");
		t.start();//b去调用a.last(),这时锁住了b,等待a的锁。(这时已将b锁住)
		Thread.currentThread().setName("MainThread");
		a.foo(b); //a去调用b.last(),等待b的锁,这时锁住了a。(这时b已经锁住)
		System.out.println("Back in main thread");
	}

	public void run() {
		b.bar(a);
		System.out.println("Back in other thread");
	}

	public static void main(String args[]) {
		new Deadlock();
	}
}



结果:
MainThread entered A.foo(B b)
RacingThread entered B.bar(A a)
RacingThread trying to call A.last()
MainThread trying to call B.last()
。。。(线程死锁在这里)

如果将线程生成的顺序改成
	Deadlock() {
		Thread.currentThread().setName("MainThread");
		a.foo(b); //a去调用b.last(),等待b的锁,这时锁住了a。(这时b已经锁住)
		Thread t = new Thread(this, "RacingThread");
		t.start();//b去调用a.last(),这时锁住了b,等待a的锁。(这时已将b锁住)
		System.out.println("Back in main thread");
	}

那么结果将成为:
MainThread entered A.foo(B b)
MainThread trying to call B.last()
Inside B.last
Back in main thread
RacingThread entered B.bar(A a)
RacingThread trying to call A.last()
Inside A.last
Back in other thread
(结果运行完毕,未死锁)


2. Java thread 中的join()
package com.java.lang.thread;

public class MyJoin extends Thread {
	private int count = 0;
	
	public MyJoin(String name, int count) {
		this.setName(name);
		this.count = count;
	}

	@Override
	public void run() {
		while(count <= 10){
			System.out.println(this.getName() + ": " + count++);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) throws Exception{
		MyJoin thread1 = new MyJoin("thread1",1);
		MyJoin thread2 = new MyJoin("thread2",2);
		thread1.start();
		thread1.join();//Waits for this thread to die. 
		thread2.start();
		
	}
}



3. Java Thread 中的暂停、唤醒和停止机制
package com.java.lang.thread;

public class MySuspendResume implements Runnable {
	private boolean pause = false;
	private boolean stop = false;
	
	public MySuspendResume() {
		super();
	}
	
	public MySuspendResume(boolean pause) {
		this();
		this.pause = pause;
	}
	
	public MySuspendResume(boolean pause, boolean stop) {
		this(pause);
		this.stop = stop;
	}

	@Override
	public void run() {
		try {
			for(;!stop;){
				System.out.print(".");
				Thread.sleep(1000);
				if(pause){
					synchronized (this) {
						this.wait();// 自己的wait()函数,但是为了让调用自己的方法wait
					}
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public void suspend(){
		this.pause = true;
		System.out.println("\tsuspended");
	}

	public void stop(){
		this.stop = true;
		System.out.println("\tstopped");
	}
	
	synchronized public void resume(){
		this.pause = false;
		System.out.println("\tresumed");
		this.notify();//自己的notify()方法,但是为了来唤醒因为自己而wait的方法
	}

	public static void main(String[] args) throws Exception{
		MySuspendResume runnable1 = new MySuspendResume();
		Thread thread1 = new Thread(runnable1);
		thread1.start();

		Thread.sleep(2000);
		runnable1.suspend();
		Thread.sleep(5000);
		runnable1.resume();
		Thread.sleep(5000);
		runnable1.stop();
	}
}


结果:
... suspended (注:输出三个点,用时2秒,然后suspended了5秒)
resumed   (注:suspended5秒之后,resumed,接着输出)
...... stopped   (住:接着输出5秒之后输出6个点,就stopped了。)


4. Java ThreadGroup的作用:
可以让不同的线程位于不同的group中,这样类似功能的thread便分到了同一组中,便于控制。如下代码是让groupA中的线程阻塞,然后groupB中的线程完成之后便唤醒groupA中的线程。
package com.java.lang.thread;

public class MyThreadGroup {
	public static void main(String[] args) {
		ThreadGroup groupA = new ThreadGroup("Group A");
		ThreadGroup groupB = new ThreadGroup("Group B");

		NewThread ob1 = new NewThread("One", groupA);
		NewThread ob2 = new NewThread("Two", groupA);
		new NewThread("Three", groupB);
		new NewThread("Four", groupB);

		groupA.list();
		groupB.list();
		Thread tga[] = new Thread[groupA.activeCount()];
		groupA.enumerate(tga);
		
		System.out.println("Suspending Group A");
		for (int i = 0; i < tga.length; i++) {
			((NewThread) tga[i]).mysuspend();
		}

		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			System.out.println("Main thread interrupted.");
		}

		System.out.println("Resuming Group A");
		for (int i = 0; i < tga.length; i++) {
			((NewThread) tga[i]).myresume();
		}

		try {
			ob1.join();// main函数会在ob1结束之后才会执行
			ob2.join();// main函数会在ob2结束之后才会执行
		} catch (Exception e) {
			System.out.println("Exception in Main thread");
		}
		System.out.println("--------The end--------");
	}

}

class NewThread extends Thread {
	boolean suspendFlag;

	NewThread(String threadname, ThreadGroup tgOb) {
		super(tgOb, threadname);
		suspendFlag = false;
		start();
	}

	public void run() {
		try {
			for (int i = 5; i > 0; i--) {
				System.out.println(getName() + ": " + i);
				Thread.sleep(1000);
				synchronized (this) {
					if (suspendFlag) {
						wait();
					}
				}
			}
		} catch (Exception e) {
			System.out.println("Exception in " + getName());
		}
	}

	void mysuspend() {
		suspendFlag = true;
	}

	synchronized void myresume() {
		suspendFlag = false;
		notify();
	}
}


结果:

One: 5
Two: 5
java.lang.ThreadGroup[name=Group A,maxpri=10]
Three: 5
    Thread[One,5,Group A]
    Thread[Two,5,Group A]
java.lang.ThreadGroup[name=Group B,maxpri=10]
    Thread[Three,5,Group B]
    Thread[Four,5,Group B]
Suspending Group A
Four: 5
Four: 4
Three: 4
Three: 3
Four: 3
Four: 2
Three: 2
Four: 1
Three: 1
Resuming Group A
Two: 4
One: 4
Two: 3
One: 3
Two: 2
One: 2
Two: 1
One: 1
--------The end--------
(注:多线程中的输出结果每次执行的时候可能不完全一致,取决于每个线程获得资源的时间)
分享到:
评论
1 楼 medicine 2013-01-04  
Thread.sleep(1000);  会使线程进入 TIMED_WAITING 状态
等待锁时是 BLOCKED 状态


  总结的不错

相关推荐

    java.lang研究

    `ThreadGroup`用于管理一组线程,而`ThreadLocal`提供线程局部变量,确保每个线程都有自己的独立副本。`ClassLoader`负责加载类,`SecurityManager`则提供了安全管理机制。 `Runnable`接口定义了`run()`方法,任何...

    java_lang包详解.pdf

    java.lang包还包含了一些与安全、线程和内存管理相关的类,如SecurityManager用于安全管理,Thread和ThreadGroup是线程相关的类,ClassLoader负责加载类,ThreadLocal为每个线程提供独立的变量副本,而Runtime类提供...

    如何解决Mybatis--java.lang.IllegalArgumentException: Result Maps collection already contains value for X

    在整合Spring、Struts2和Mybatis的过程中,可能会遇到各种问题,其中之一就是`java.lang.IllegalArgumentException: Result Maps collection already contains value for X`。这个问题通常出现在Mybatis配置文件中,...

    java-java-lang包.pdf

    - ThreadGroup:表示一个线程组,用于组织管理相关的线程。 - ThreadLocal:用于提供线程内部的局部变量。 6. 实用工具类: - String:表示字符串,提供了丰富的字符串操作方法。 - StringBuffer:表示字符序列...

    java_javalang包.pdf

    最后,`Thread`和`ThreadGroup`类构成了Java的多线程机制,`ThreadLocal`则提供线程私有的变量,确保每个线程都有自己的副本,不会互相干扰。 总的来说,`java.lang`包是Java程序的基础,其提供的类和接口构成了...

    java-1.6中文API.

    5. **多线程**:`java.lang.Thread`类和`java.util.concurrent`包提供了线程管理和并发控制,如`Runnable`接口、`ThreadGroup`、`Semaphore`、`ExecutorService`等。 6. **异常处理**:`java.lang.Throwable`及其...

    java 1.6 中文api文档

    5. **多线程**:`java.lang.Thread` 类和相关接口定义了多线程编程的基本概念,如 `Runnable` 和 `ThreadGroup`。Java 1.6 对线程同步和通信进行了优化,引入了更高级的并发工具,如 `java.util.concurrent` 包下的 ...

    线程池程序-threadGroup

    线程组是Java中对线程进行组织和管理的一种方式,它是`java.lang.ThreadGroup`类的实例。线程组可以包含线程和其他线程组,允许我们对一组线程进行分组操作,比如监控、统计或安全管理。 在描述中提到,“没有用...

    Java获取系统信息(cpu,内存,硬盘,进程等)的相关方法.pdf

    import mytools.java.lang.management.ManagementFactory; public class WindowsInfoUtil { private static final int CPUTIME = 500; private static final int PERCENT = 100; private static final int ...

    Java多线程

    - **java.lang.Thread类的实例**:表示线程对象,拥有自己的变量和方法,存在于堆上。 - **线程的执行**:实际执行的线程行为。 Java中的线程可以通过实现`java.lang.Thread`类或继承`java.lang.Runnable`接口来...

    Java线程资料.pdf

    5. 线程组和线程优先级:ThreadGroup和线程优先级也是管理线程时的重要概念。线程组提供了组织和控制一组线程的方式,线程优先级则允许我们对线程调度的优先顺序进行设置。 6. Java虚拟机(JVM)对线程的支持:JVM...

    Java多线程培训讲义.docx

    线程组通过`ThreadGroup`类实现,可以嵌套创建,形成树状结构。线程在创建时可以指定其所属的线程组。 总结来说,Java多线程提供了强大的工具和机制来处理并发问题,包括线程的创建、调度、同步和互斥,以及线程组...

    Java核心API需要掌握的程度

    17. **Thread/ThreadGroup/ThreadLocal/InheritableThreadLocal**:线程相关的类,提供了多线程编程的支持。 18. **Throwable/Error/AssertionError/LinkageError/ClassCircularityError/ClassFormatError/...

    Java程序设计习题

    - B、`java.lang.ThreadGroup`: 线程组的实现。 - C、`java.lang.Thread`: 线程的实现。 - D、`java.lang.Runnable`: 可运行接口。 - **答案**: B - **解析**: `ThreadGroup`类提供了线程组的功能,用于管理一组...

    线程和Java Applet讲解

    Java中的线程模型由三部分构成:虚拟CPU(封装在`java.lang.Thread`类中)、执行的代码(传递给`Thread`类)和处理的数据(传递给`Thread`类)。创建线程有两种主要方式: 1. **继承`Thread`类**:自定义一个类继承...

    java 线程

    - 学习Java的线程模型,如JVM如何调度线程,可以阅读JDK源码中`java.lang.Thread`和`java.lang.ThreadGroup`的相关实现。 - 分析`synchronized`和`volatile`的底层实现,了解内存模型(Java Memory Model)对并发...

    JAVA100例之实例63 JAVA线程群组

    比如,使用`ThreadGroup.interrupt()`中断群组内的所有线程,或者通过`ThreadGroup.stop()`强制停止(尽管不推荐,因为这种方式可能导致资源泄露和其他问题)。 此外,实例可能还会涉及Java并发库中的其他组件,如`...

    Java Thread类1

    Java的线程是通过`java.lang.Thread`类来创建和管理的。当虚拟机启动时,会有一个主线程,即main方法所在的线程。创建新的线程通常涉及以下步骤: 1. **创建Thread实例**:首先,你需要创建一个Thread类的实例,这...

Global site tag (gtag.js) - Google Analytics