并发编程3-线程调度

状态图:

方法说明:

run 线程运行的主体

yield() 放弃当前的时间片进入可运行状态,可以被再次选中

start() 线程进入可运行阶段

sleep(), 阻塞一定的时间,会持有锁

t2.join() 等待t2线程运行结束,会持有锁,有可能会死锁

wait()   锁对象的方法,持有锁对象的线程释放锁,进入阻塞队列等待notify

notify() 锁对象的方法,唤醒一个该锁对象阻塞队列中的线程

notifyAll()  锁对象的方法,唤醒所有该锁对象阻塞队列中的线程

wait , notify, notifyAll

class SynClass{
	public void execute(){
		System.out.println(Thread.currentThread().getName());
	}
}
final SynClass sc = new SynClass();
		Thread[] ts = new Thread[10];
		for (int i = 0; i < 10; i++) {
			ts[i] = new Thread("thread" + i){
				public void run() {
					synchronized (sc) {
						try {
							sc.wait();
							sc.execute();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				};
			};
		}

		for (Thread t : ts) {
			t.start();
		}

		TimeUnit.SECONDS.sleep(1);

		synchronized (sc) {
			sc.notify();
			sc.notify();
		}

		while(true);

会打印:

thread1
thread0

如果把其中的sc.notify()换为notifyAll()则会打印出所有的线程。

interrupt

在阻塞的方法比如wait() 或者sleep()中会有while(interruped()) throws InterruptedException()方法,

interrupt()方法会设置状态为打断状态

interrupted()方法如果是打断状态返回true,同时设置打断状态为false;

生产者消费者

public class Storage {
	private String[] products = new String[2];
	private int index = -1;

	public synchronized void  produce(String product) throws InterruptedException{
		while(index == products.length - 1){
			System.out.println("超出上限无法生产");
			this.wait();
		}

		products[++index] = product;
		System.out.println("生产了" + product);
		this.notify();
	}

	public synchronized String consume() throws InterruptedException{
		while(index == -1){
			System.out.println("没有库存了");
			this.wait();
		}
		this.notify();
		return products[index--];
	}

	public static void main(String[] args) {
		final Storage s = new Storage();
		new Thread(){
			public void run() {
				while(true){
					try {
						System.out.println("消费了" + s.consume());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

					try {
						TimeUnit.MILLISECONDS.sleep(new Random(1000).nextLong());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();

		new Thread(){
			public void run() {
				while(true){
					try {
						s.produce("product" + new Random().nextInt(100));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

					try {
						TimeUnit.MILLISECONDS.sleep(new Random(1000).nextLong());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();

		while(true);
	}
}

一个线程生产,一个线程消费。

生产超出上限则wait消费,没超出则进行生产,开始生产了就应该通知消费者可以消费了。

消费线程没有商品则wait生产,有商品就消费,同时通知生产者可以继续生产了。

时间: 2024-12-06 03:47:56

并发编程3-线程调度的相关文章

Java并发编程相关面试问题

基础概念 1.什么是原子操作?在Java Concurrency API中有哪些原子类(atomic classes)? 原子操作(atomic operation)意为"不可被中断的一个或一系列操作" .处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作. 在Java中可以通过锁和循环CAS的方式来实现原子操作. CAS操作--Compare & Set,或是 Compare & Swap,现在几乎所有的CPU指令都支持CAS的原子操作. 原子操作是

转 Java并发编程:volatile关键字解析

volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java  5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情.由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatile关键字的实现原理,最后给出了几个使用vol

《C#并发编程经典实例》—— 发送通知给上下文

声明:本文是<C#并发编程经典实例>的样章,感谢图灵授权并发编程网站发布样章,禁止以任何形式转载此文. 问题 Rx 尽量做到了线程不可知(thread agnostic).因此它会在任意一个活动线程中发出通知(例如 OnNext). 但是我们通常希望通知只发给特定的上下文.例如 UI 元素只能被它所属的 UI 线程控制, 因此,如果要根据 Rx 的通知来修改 UI,就应该把通知"转移"到 UI 线程. 解决方案 Rx 提供了 ObserveOn 操作符,用来把通知转移到其他

《Java线程与并发编程实践》- 第1章 Thread和Runnable

第1章 Thread和Runnable Java线程与并发编程实践 Java程序是通过线程执行的,线程在程序中具有独立的执行路径.当多条线程执行时,它们彼此之间的路径可以不同.举个例子,一条线程可能在执行switch语句的某个case分支,另一条线程很可能在执行其他case分支. 每个Java应用程序都有一个执行main()函数的默认主线程.应用程序也可以创建线程在后台操作时间密集型任务,以确保对用户的响应.这些封装了代码执行序列的线程对象就被称为runnable. Java虚拟机给每条线程分配

Java并发编程:volatile关键字详细解析_java

volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情.由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatile关键字的实现原理,最后给出了几个使用vola

Java并发编程系列之一:并发机制的底层原理

前言 并发编程的目的是让程序运行更快,但是使用并发并不定会使得程序运行更快,只有当程序的并发数量达到一定的量级的时候才能体现并发编程的优势.所以谈并发编程在高并发量的时候才有意义.虽然目前还没有开发过高并发量的程序,但是学习并发是为了更好理解一些分布式架构.那么当程序的并发量不高,比如是单线程的程序,单线程的执行效率反而比多线程更高.这又是为什么呢?熟悉操作系统的应该知道,CPU是通过给每个线程分配时间片的方式实现多线程的.这样,当CPU从一个任务切换到另一个任务的时候,会保存上一个任务的状态,

并发编程(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题

请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比"原生的"POSIX mutex,condition variables好用.然后我们会通过分析boost相关源码看一下boost linux是如何对pthread_mutex_t和pthread_cond_t进行的封装. 首先看一下condition_variable_any的具体实现,代码路径:/

Python中利用生成器实现的并发编程

  这篇文章主要介绍了简单介绍Python中利用生成器实现的并发编程,使用yield生成器函数进行多进程编程是Python学习进阶当中的重要知识,需要的朋友可以参考下 我们都知道并发(不是并行)编程目前有四种方式,多进程,多线程,异步,和协程. 多进程编程在python中有类似C的os.fork,当然还有更高层封装的multiprocessing标准库,在之前写过的python高可用程序设计方法中提供了类似nginx中master process和worker process间信号处理的方式,保

《GO并发编程实战》—— 原子操作

声明:本文是<Go并发编程实战>的样章,感谢图灵授权并发编程网站发布样章,禁止以任何形式转载此文. 我们已经知道,原子操作即是进行过程中不能被中断的操作.也就是说,针对某个值的原子操作在被进行的过程当中,CPU绝不会再去进行其它的针对该值的操作.无论这些其它的操作是否为原子操作都会是这样.为了实现这样的严谨性,原子操作仅会由一个独立的CPU指令代表和完成.只有这样才能够在并发环境下保证原子操作的绝对安全. Go语言提供的原子操作都是非侵入式的.它们由标准库代码包sync/atomic中的众多函

我为什么喜欢用C#来做并发编程

题记:就语言和运行时层面,C#做并发编程一点都不弱,缺的是生态和社区. 硅谷才女朱赟(我的家门)昨天发了一篇文章<为什么用 Java -- 关于并发编程>,让大家学习了Java中如何进行并发编程的一些基本知识.作为一个将近15年的.NET程序员,我觉得有必要给大家补充介绍一下C#进行并发编程的知识(当然不会太深入讲解).这篇文章无意进行技术比较,毕竟技术只是工具(大同小异,各有千秋),主要还是看用工具的人. 并发(英文Concurrency),其实是一个很泛的概念,字面意思就是"同时