java之 ------ 多线程(交互线程)

1、运行结果不惟一,取决于线程调度

2、线程执行被打断时出现错误

3、线程互斥和临界区管理

1)操作系统对共享一个变量的若干线程进入各自临界区有以下3个调度原则:

2)一次至多一个线程能够在它的临界区内。

3)不能让一个线程无限地留在它的临界区内。

4)不能强迫一个线程无限地等待进入它的临界区。特别地,进入临界区的任一线程不能妨碍正等待进入的其他线程的进展。

4、同步语句   synchronized (对象)

同步方法  synchronized  方法声明   方法声明synchronized(this){  方法体  }

5、银行账户的存款取款线程

Account.c

package p25;

public class Account {
	private String name;//储户姓名
	private double balance;//账户余额

	public Account(String name) {
		this.name = name;
		this.balance = 0;
	}
	//查询余额
	public double balance() {
		return this.balance;
	}

	public String getName() {
		return this.name;
	}
	//存款操作
	public void put(double value) {
		if (value > 0) {
			this.balance += value;
		}
	}
	//取款操作
	public double get(double value) {
		if (value > 0) {
			if (value < this.balance) {//够取
				this.balance -= value;
			} else {
				value = this.balance;
				this.balance = 0;
			}
			return value;
		}
		return 0;
	}
}

class Save extends Thread {
	private Account account;
	private double value;

	public Save(Account account, double value) {
		this.account = account;
		this.value = value;
	}

	public void run() {
		synchronized (account) {//声明临界区,锁定当前account对象
			double howmuch = this.account.balance();//查看账户余额
			try {
				sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			this.account.put(this.value);
			double howmuch2 = this.account.balance();//查看账户余额
			System.out.println(this.account.getName() + "账户: 现有" + howmuch
					+ ",存入" + this.value + ",余额为" + howmuch2);
		}
	}
}

class Fetch extends Thread {
	private Account account;
	private double value;

	public Fetch(Account account, double value) {
		this.account = account;
		this.value = value;
	}

	public void run() {
		synchronized (account) {
			double howmuch = this.account.balance();
			try {
				sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			double v = this.account.get(this.value);
			double howmuch2 = this.account.balance();
			System.out.println(this.account.getName() + "账户: 现有" + howmuch
					+ ",取出" + v + ",余额为" + howmuch2);
		}
	}
}

class Func extends Thread {
	private Account account;
	private double value;

	public Func(Account account, double value) {
		this.account = account;
		this.value = value;
	}

	public void run() {
		fun();
	}

	synchronized void fun(){
		double howmuch = this.account.balance();
		try {
			sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.account.put(this.value);
		double v = this.account.get(this.value);
		double howmuch2 = this.account.balance();
		System.out.println(this.account.getName() + "账户: 现有" + howmuch + ",取出"
				+ v + ",余额为" + howmuch2);
	}

}

Bank.c

package p25;

public class Bank {

	public static void main(String[] args) {
		Account wang = new Account("wang");
		(new Save(wang,100)).start();
		(new Save(wang,200)).start();
		(new Fetch(wang,100)).start();

		Account li=new Account("li");
		(new Save(li,300)).start();

		Account xu=new Account("xu");
		(new Func(xu,100000)).start();
	}
}

注:必须要声明临界区,锁定account对象,不然会出错

正确结果:

错误结果:

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 06:24:36

java之 ------ 多线程(交互线程)的相关文章

java中多线程的线程同步死锁问题

/* *定义一个多线程 */ package com.thread; public class TicketThread2 implements Runnable { //定义1000张票 public static int ticket = 100; Object obj = new Object(); // public boolean flag = false; // public boolean exit = false; @Override public void run() { //

Java:多线程,线程池,使用CompletionService通过Future来处理Callable的返回结果

1. 背景 在Java5的多线程中,可以使用Callable接口来实现具有返回值的线程.使用线程池的submit方法提交Callable任务,利用submit方法返回的Future存根,调用此存根的get方法来获取整个线程池中所有任务的运行结果. 方法一:如果是自己写代码,应该是自己维护一个Collection保存submit方法返回的Future存根,然后在主线程中遍历这个Collection并调用Future存根的get()方法取到线程的返回值. 方法二:使用CompletionServic

java核心-多线程(4)-线程类基础知识

1.并发 <1>使用并发的一个重要原因是提高执行效率.由于I/O等情况阻塞,单个任务并不能充分利用CPU时间.所以在单处理器的机器上也应该使用并发. <2>为了实现并发,操作系统层面提供了.但是进程的数量和开销都有限制,并且多个进程之间的数据共享比较麻烦.另一种比较轻量的并发实现是使用线程,一个进程可以包含多个线程.线程在进程中没有数量限制, 数据共享相对简单.线程的支持跟语言是有关系的.Java 语言中支持多线程. <3>Java 中的多线程是抢占式的.这意味着一个任

Java自学-多线程 交互

Java 线程之间的交互 wait和notify 线程之间有交互通知的需求,考虑如下情况: 有两个线程,处理同一个英雄. 一个加血,一个减血. 减血的线程,发现血量=1,就停止减血,直到加血的线程为英雄加了血,才可以继续减血 步骤 1 : 不好的解决方式 故意设计减血线程频率更高,盖伦的血量迟早会到达1 减血线程中使用while循环判断是否是1,如果是1就不停的循环,直到加血线程回复了血量 这是不好的解决方式,因为会大量占用CPU,拖慢性能 package charactor; public c

java核心技术-多线程之线程基础

说起线程,无法免俗首先要弄清楚的三个概念就是:进程.线程.协程.OK,那什么是进程,什么是线程,哪协程又是啥东西.进程:进程可以简单的理解为运行在操作系统中的程序,程序时静态代码,进程是动态运行着的代码,程序的运行需要向操作系统申请资源比如内存,文件句柄等,特别强调的是进程申请的资源都是独立的,也就是进程与进程之间资源是独立的.它被操作系统调度,所以进程是相对于操作系统的:线程:线程是进程中程序执行任务的那个,它共享着进程申请的资源:协程:可以简单的说是线程制造的轻量线程.讲完了基本的概念看看三

Java学习-多线程交互

1-生产者消费者问题 1. 使用栈来存放数据 1.1 把栈改造为支持线程安全 1.2 把栈的边界操作进行处理,当栈里的数据是0的时候,访问pull的线程就会等待. 当栈里的数据是200的时候,访问push的线程就会等待2. 提供一个生产者(Producer)线程类,生产随机大写字符压入到堆栈3. 提供一个消费者(Consumer)线程类,从堆栈中弹出字符并打印到控制台4. 提供一个测试类,使两个生产者和三个消费者线程同时运行 1 package multiplethread; 2 3 impor

Java创建多线程和线程安全集合Vector

public class Test { public static Vector<String> data = new Vector<String>(); public static void main(String[] args) { for (int i = 0; i < 100; i++) { data.add("data" + i); } for (int i = 0; i < 3; i++) { Thread t = new Thread(

Java多线程之线程的创建

好久没有更博客了,最近一直在忙工作的事情.现在终于空下来了,这2天会抓紧时间整理多线程和socket,把JavaSE结束掉. 关于多线程,首先会涉及到哪些东西呢?首先要了解线程,为什么要使用线程,线程有什么优势,线程和进程有什么区别呢?了解过大致的线程内容后,就应该编码来实现Java的多线程了.首先2种方式来创建线程类,然后调用对应的API来控制线程.然后还剩下一个最大的也是最重要的一块知识,就是线程同步.前面那些了解线程的生命周期就可以,实际编码中并不会多次写到那些编码,但是线程的同步经常要用

Java之------多线程(从基础到加强及交互线程)

一.基础篇: 1.线程的定义 线程(thread)是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位. 2.线程的属性 并发性,共享性,动态性,结构性 3.线程的状态 4.线程的调度 ★主要是通过实现Runnable接口和继承Thread类来实现线程的调度和操作 a.Runnable接口(里面就一个run方法,只要通过重写run方法就可以实现自己想要的线程功能) [java] view plain copy public interface Runnable { publ

Java多线程 2 线程的生命周期和状态控制

一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable). 注意:不能对已经启动的线程再次调用start()方法,否则会出现Java.lang.IllegalThreadStateException异常. 2.就绪状态 处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列(尽管是采用队列形式,事实上,把它