`
flyPig
  • 浏览: 139840 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

jdk1.5的多线程总结二

    博客分类:
  • Java
阅读更多
新的Synchronizer:
Java 5.0里新加了4个协调线程间进程的同步装置,它们分别是Semaphore, CountDownLatch, CyclicBarrier和Exchanger。

Semaphore:
用来管理一个资源池的工具,Semaphore可以看成是个通行证,线程要想从资源池拿到资源必须先拿到通行证,Semaphore提供的通行证数量和资源池的大小一致。如果线程暂时拿不到通行证,线程就会被阻断进入等待状态。
public class Pool {
	List<String> pool = null;

	Semaphore pass = null;

	public Pool(int size) {
		// 初始化资源池
		pool = new ArrayList<String>();
		for (int i = 0; i < size; i++) {
			pool.add("Resource " + i);
		}
		// Semaphore的大小和资源池的大小一致
		pass = new Semaphore(size);
	}

	public String get() throws InterruptedException {
		// 获取通行证,只有得到通行证后才能得到资源
		pass.acquire();
		return getResource();
	}

	public void put(String resource) {
		// 归还通行证,并归还资源
		pass.release();
		releaseResource(resource);
	}

	private synchronized String getResource() {
		String result = pool.get(0);
		pool.remove(0);
		System.out.println("Take " + result);
		return result;
	}

	private synchronized void releaseResource(String resource) {
		System.out.println("return " + resource);
		pool.add(resource);
	}
}

public class SemaphoreTest {
	public static void main(String[] args) {

		final Pool aPool = new Pool(2);
		Runnable worker = new Runnable() {
			public void run() {
				String resource = null;
				try {
					// 取得resource
					resource = aPool.get();
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
				// 用resource做工作
				System.out.println("I worked on " + resource);
				// 归还resource
				aPool.put(resource);
			}
		};

		ExecutorService service = Executors.newCachedThreadPool();
		for (int i = 0; i < 20; i++) {
			service.submit(worker);
		}
		service.shutdown();
	}
}


CountDownLatch:
CountDownLatch是个计数器,它有一个初始数,等待这个计数器的线程必须等到计数器倒数到零时才可继续。比如说一个Server启动时需要初始化4个部件,Server可以同时启动4个线程去初始化这4个部件,然后调用CountDownLatch(4).await()阻断进入等待,每个线程完成任务后会调用一次CountDownLatch.countDown()来倒计数, 当4个线程都结束时CountDownLatch的计数就会降低为0,此时Server就会被唤醒继续下一步操作。CountDownLatch的方法主要有:
await():使调用此方法的线程阻断进入等待
countDown(): 倒计数,将计数值减1
getCount(): 得到当前的计数值
public class Server {
	public static void main(String[] args) throws InterruptedException{
		//一个server调了三个ComponentThread分别去启动三个组件,然后server等到组件都启动了再继续
        System.out.println("Server is starting.");
        //初始化一个初始值为3的CountDownLatch
        CountDownLatch latch = new CountDownLatch(3);
        //起3个线程分别去启动3个组件
        ExecutorService service = Executors.newCachedThreadPool();
        service.submit(new ComponentThread(latch, 1));
        service.submit(new ComponentThread(latch, 2));
        service.submit(new ComponentThread(latch, 3));
        service.shutdown();
        //进入等待状态
        latch.await();
        //当所需的三个组件都完成时,Server就可继续了
        System.out.println("Server is up!");
  }
}
public class ComponentThread implements Runnable {

	CountDownLatch latch;

	int ID;

	public ComponentThread(CountDownLatch latch, int ID) {
		this.latch = latch;
		this.ID = ID;
	}

	public void run() {
		System.out.println("Component " + ID + " initialized!");
		// 将计数减一
		latch.countDown();
	}
}


CyclicBarrier:
CyclicBarrier类似于CountDownLatch也是个计数器,不同的是CyclicBarrier数的是调用了CyclicBarrier.await()进入等待的线程数,当线程数达到了CyclicBarrier初始时规定的数目时,所有进入等待状态的线程被唤醒并继续。CyclicBarrier就象它名字的意思一样,可看成是个障碍,所有的线程必须到齐后才能一起通过这个障碍。CyclicBarrier初始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。
CyclicBarrier提供以下几个方法:
await():进入等待
getParties():返回此barrier需要的线程数
reset():将此barrier重置
public class CyclicBarrierTest {
	public static void main(String[] args) throws InterruptedException,
			BrokenBarrierException, TimeoutException {
		// 两个线程分别在一个数组里放一个数,当这两个线程都结束后,主线程算出数组里的数的和
		final int[] array = new int[2];
		CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() {
			public void run() {
				System.out.println("Total is:" + (array[0] + array[1]));
			}
		});

		// 启动线程
		new Thread(new ComponentThread(barrier, array, 0)).start();
		new Thread(new ComponentThread(barrier, array, 1)).start();
	}
}
public class ComponentThread implements Runnable{
	CyclicBarrier barrier;

    int ID;

    int[] array;

    public ComponentThread(CyclicBarrier barrier, int[] array, int ID) {
          this.barrier = barrier;
          this.ID = ID;
          this.array = array;
    }

    public void run() {
          try {
                array[ID] = new Random().nextInt();
                System.out.println(ID+ " generates:"+array[ID]);
                //该线程完成了任务等在Barrier处
                barrier.await();
          } catch (BrokenBarrierException ex) {
                ex.printStackTrace();
          } catch (InterruptedException ex) {
               ex.printStackTrace();
          }
    }
}

Exchanger:
让两个线程可以互换信息。这个跟生产消费模式有点不同,生产消费模式是生产者和消费者对同一个数据争用,这里是对两个同类型的数据争用,用完就互换。用一个例子来解释比较容易。例子中服务生线程往空的杯子里倒水,顾客线程从装满水的杯子里喝水,然后通过Exchanger双方互换杯子,服务生接着往空杯子里倒水,顾客接着喝水,然后交换,如此周而复始。两个线程同时只对自己的那个数据操作。


BlockingQueue接口
BlockingQueue是一种特殊的Queue,若BlockingQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态直到BlocingkQueue进了新货才会被唤醒。同样,如果BlockingQueue是满的任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有新的空间才会被唤醒继续操作。BlockingQueue提供的方法主要有:
add(anObject): 把anObject加到BlockingQueue里,如果BlockingQueue可以容纳返回true,否则抛出IllegalStateException异常。
offer(anObject):把anObject加到BlockingQueue里,如果BlockingQueue可以容纳返回true,否则返回false。
put(anObject):把anObject加到BlockingQueue里,如果BlockingQueue没有空间,调用此方法的线程被阻断直到BlockingQueue里有新的空间再继续。
poll(time):取出BlockingQueue里排在首位的对象,若不能立即取出可等time参数规定的时间。取不到时返回null。
take():取出BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的对象被加入为止。

根据不同的需要BlockingQueue有4种具体实现:
ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小。其所含的对象是以FIFO(先入先出)顺序排序的。
LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定。其所含的对象是以FIFO(先入先出)顺序排序的。LinkedBlockingQueue和ArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,导致LinkedBlockingQueue的数据吞吐量要大于ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于ArrayBlockingQueue。
PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。
SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的。
下面是用BlockingQueue来实现经典的Producer和Consumer模式
public class BlockingQueueTest {
	static BlockingQueue<String> basket;

	public BlockingQueueTest() {
		// 定义了一个大小为2的BlockingQueue,也可根据需要用其他的具体类
		basket = new ArrayBlockingQueue<String>(2);
	}

	class Producor implements Runnable {

		public void run() {
			while (true) {
				try {
					// 放入一个对象,若basket满了,等到basket有位置
					basket.put("An apple");
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			}
		}
	}

	class Consumer implements Runnable {
		public void run() {
			while (true) {
				try {
					// 取出一个对象,若basket为空,等到basket有东西为止
					String result = basket.take();
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			}
		}
	}

	public void execute() {
		for (int i = 0; i < 10; i++) {
			new Thread(new Producor()).start();
			new Thread(new Consumer()).start();
		}
	}

	public static void main(String[] args) {
		BlockingQueueTest test = new BlockingQueueTest();
		test.execute();
	}
}


Atomics 原子级变量
主要的类有AtomicBoolean, AtomicInteger, AotmicIntegerArray, AtomicLong, AtomicLongArray, AtomicReference ……。这些原子量级的变量主要提供两个方法:
compareAndSet(expectedValue, newValue): 比较当前的值是否等于expectedValue,若等于把当前值改成newValue,并返回true。若不等,返回false。
getAndSet(newValue): 把当前值改为newValue,并返回改变前的值。
这些原子级变量利用了CPU的硬件支持可把两步操作合为一步的功能,避免了不必要的锁定,提高了程序的运行效率。
分享到:
评论

相关推荐

    jxl.jar与jdk1.5和jxl.jar与jdk1.6匹配

    总结来说,jxl.jar在JDK1.5和JDK1.6环境下都可以使用,但每个新版本的JDK都可能带来性能差异和潜在的兼容性问题。因此,进行详尽的测试和评估是确保项目稳定运行的关键。同时,开发者也需要关注和考虑更新的库和技术...

    jdk1.5 线程并发与线程池的使用

    在Java编程语言中,线程并发和线程池是多任务执行的核心概念,尤其是在...熟练掌握这些工具,能帮助开发者编写出更加稳定、高效的多线程应用程序。通过深入学习和实践,可以更好地理解和利用这些特性,优化程序性能。

    官方JDK1.5版本

    1. 并发库(Concurrent Utilities):引入了丰富的并发工具类,如`java.util.concurrent`包,包括线程池、并发集合等,极大地改善了多线程编程的效率和可靠性。 2. NIO.2(New I/O):增强了Java的I/O性能,增加了...

    jdk1.5 1.6 1.7的新特征总结

    1. 并发工具库的改进:包括`java.util.concurrent`包中更多线程安全的数据结构和并发工具,如`ConcurrentHashMap`,`Phaser`等。 2. 轻量级注解处理:允许在编译时处理注解,无需生成额外的源代码或字节码。 3. 动态...

    JDK1.5-1.6-1.7之新特性总结-1

    JDK 1.5增加了大量并发编程的工具类,如`java.util.concurrent`包下的`ExecutorService`、`Future`、`Semaphore`等,它们提供了更高效和安全的多线程处理方式。 **10. 遍历Map的键值对(For-Each Loop over Maps)*...

    jdk-1_5_0_01-windows-i586-p.rar

    枚举在多线程、权限控制和设计模式等方面都有着广泛的应用,提升了代码的规范性和可维护性。 此外,JDK 1.5还推出了变量类型推断(varargs)功能,这使得方法可以接受任意数量的同一类型的参数。通过在方法声明中...

    张孝祥Java多线程与并发库高级应用笔记

    张孝祥的Java多线程与并发库高级应用笔记涵盖了从传统线程技术到JDK1.5并发库的全面内容,不仅加深了对线程基本原理的认识,还介绍了现代Java并发编程的最佳实践。对于希望提升多线程编程技能的Java开发者来说,这是...

    jdk-1_5_0_22-windows-i586-p

    9. **并发编程改进**:引入了`java.util.concurrent`包,包含线程池、并发集合等工具,提高了多线程程序的编写效率和性能。 **环境变量配置** 安装JDK 1.5 Update 22后,为了能正确运行Java程序,需要设置一些系统...

    jcifs:JDK 1.5 的修补 jcifs - http

    这只是一个基础的示例,实际使用中,jcifs库可以处理更复杂的情况,如多线程访问、错误处理和高级权限控制。 总结来说,jcifs库为Java开发者提供了一个强大且灵活的工具,使他们能够在Java应用程序中无缝地集成CIFS...

    jdk-1_5_0_22-linux-amd64.bin

    描述中提到"linux版的jdk1.5,官网下载",这确认了JDK的版本是1.5,也被称为Java 5,它是在Linux平台上官方提供的版本,并且是从官方网站下载的。Java 5是一个重要的Java版本,引入了许多新特性,对Java语言的演进...

    经典Java多线程与并发库高级应用

    总结来说,Java多线程与并发库的高级应用,既包括了传统的多线程编程技术,也包含了JDK 1.5之后引入的高级并发工具和特性。掌握这些知识点对于任何想要在Java编程领域深入发展的开发者来说,都是非常必要的。

    JDK1.6百度云下载

    JDK1.6是Java发展史上的一个重要版本,它在JDK1.5的基础上进行了大量的改进和优化,提供了更多的特性和功能。 ### 二、JDK1.6的主要特性 1. **性能优化**:JDK1.6对垃圾回收机制进行了改进,提升了程序运行时的...

    jdk_api_1_6中文版

    4. 多线程改进:JDK 1.6增强了线程管理,包括线程池的改进,使得开发者可以更有效地控制线程的生命周期和资源分配。 5. 新的Swing组件:JDK 1.6对Swing库进行了更新,增加了新的组件和布局管理器,提升了图形用户...

    jdk1.8下载附安装教程.zip

    JDK 1.8引入了一些重要的新特性,如Lambda表达式、Stream API、方法引用来简化代码,以及接口的默认方法和静态方法,增强了多线程处理的并发工具类等。这些特性极大地提高了Java开发的效率和代码的可读性。 总结来...

    JDK1.6英文帮助文档

    2. **网络与多线程**:如java.net和java.nio包,支持网络通信;java.concurrent包提供了高级并发和线程管理工具。 3. **图形界面**:java.awt和javax.swing包提供了图形用户界面(GUI)组件和布局管理器。 4. **...

    jdk_1.6.0_45

    - **泛型**:JDK 1.5引入了泛型,允许在定义类、接口和方法时指定参数类型,提高了代码的类型安全性和重用性。 - **增强的for循环(foreach)**:简化了遍历集合和其他迭代器支持的数据结构的代码。 - **动态代理*...

    jdk1.6 64位 JAVA开发JDK

    9. **并发编程工具**:`java.util.concurrent`包中的类和接口进一步丰富,如CountDownLatch、CyclicBarrier和ForkJoinPool等,使得多线程编程更为方便。 10. **JMX(Java Management Extensions)**:提供了更强大...

    JAVA-基础多线程

    #### 五、JDK1.5之后的高级同步工具 1. **`ReentrantLock`**: - `ReentrantLock`是Java 1.5之后引入的一个可中断、可轮询、可定时的锁。 - 示例代码: ```java private ReentrantLock lock = new ...

Global site tag (gtag.js) - Google Analytics