JAVA学习笔记之多线程专题(一):线程同步安全处理

关于多线程操作,我相信大家都不陌生,如何开启一个线程之类我想就不用太详细的去描述,今天我们就来讲讲线程同步的安全的问题。

对于线程同步安全问题,一般是一个多线程对同一个资源同时操作的时候,会出现资源同时操作造成线程不安全的问题。那么这个时候我们需要去对公共资源进行同步保护。这个时候有三种情况

1、同步代码块,这个同步的锁是任意一个对象;

2、方法同步,这个同步的锁就是该方法所在的类;

3、静态方法同步,这个同步的锁是该方法所在类的字节码。

接下来,我们举一个例子来说明多线程对同一个资源进行操作的时候,如何达到资源同步安全的问题。我们以生产消费的例子,生产一个商品,消费一个商品的循环。同时讲解线程同步中线程等待和唤醒的用法。

请看代码:

public class ThreadTest {

	public static void main(String[] args) {

		// 资源
		Resources r = new Resources();
		// 生产工厂
		Producer pro = new Producer(r);
		// 消费者
		Consumer con = new Consumer(r);

		// 四个线程同时进行生产和消费,实现生产一个消费一个,避免出现对资源的重复混乱应用
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);

		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}

	public static class Resources {
		public Resources() {
		};

		// 产品名称
		private String name;
		// 产品序号
		private int count = 1;
		// 循环标记位
		private boolean flag = false;

		// 生产方法
		public synchronized void produce(String name) {
			// 循环标记位
			while (flag) {
				try {
					this.wait();
				} catch (Exception e) {
				}
			}
			// 生产出一个产品
			this.name = name + "--" + count++;
			System.out.println(Thread.currentThread().getName() + "制造一个商品"
					+ this.name);
			// 标记位转换,进入循环
			flag = true;
			// 为避免唤醒的线程队列中的第一个线程不是消费线程,我们选择全部唤醒
			this.notifyAll();

		}

		// 消费方法
		public synchronized void consume() {
			while (!flag) {
				try {
					this.wait();
				} catch (Exception e) {
				}
			}

			System.out.println(Thread.currentThread().getName() + "消耗一个商品"
					+ this.name);
			// 标记位转换,进入循环
			flag = false;
			// 为避免唤醒的线程队列中的第一个线程不是生产线程,我们选择全部唤醒
			this.notifyAll();

		}

	}

	// 生产者
	static class Producer implements Runnable {

		private Resources res;

		Producer(Resources res) {

			this.res = res;
		}

		public void run() {
			while (true) {
				res.produce("商品");

			}

		}
	}

	// 消费者
	static class Consumer implements Runnable {

		private Resources res;

		Consumer(Resources res) {

			this.res = res;
		}

		public void run() {
			while (true) {
				res.consume();

			}

		}
	}

}

我们发现,在上述过程中,我们会唤醒所有的等待线程,然后在根据循环标示为去控制生产与消费。这样总给是非常不好的感觉。当线程多的时候,会造成线程浪费。在JDK5.0之后,提供了线程同步锁Lock类来解决这一个问题。使用Lock类可以替代同步关键字来达到对公共资源的保护。我看直接看代码:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadTest2 {

	public static void main(String[] args) {

		Resource r = new Resource();

		Producer pro = new Producer(r);

		Consumer con = new Consumer(r);

		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);
		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}

	static class Resource {
		// 新建一个锁
		private Lock lock = new ReentrantLock();
		private String name;
		private int count = 1;
		private boolean flag = false;
		// 拿到对应的唤醒条件
		private Condition proCondition = lock.newCondition();
		private Condition conCondition = lock.newCondition();

		public void product(String name) {
			// 上锁
			lock.lock();
			try {
				while (flag) {
					// 等待
					proCondition.await();
				}
				this.name = name + "--" + count++;
				System.out.println(Thread.currentThread().getName() + "生产者"
						+ this.name);
				flag = true;
				// 唤醒消费线程
				conCondition.signal();
			} catch (Exception e) {
			} finally {
				// 解锁
				lock.unlock();

			}
		}

		public void consume() {
			// 上锁
			lock.lock();
			try {
				while (!flag) {
					conCondition.wait();
				}
				System.out.println(Thread.currentThread().getName() + "消费者----"
						+ this.name);
				flag = false;
				// 唤醒生产者
				proCondition.signal();
			} catch (Exception e) {
			} finally {
				// 解锁
				lock.unlock();

			}

		}

	}

	static class Producer implements Runnable {

		private Resource res;

		Producer(Resource res) {

			this.res = res;
		}

		public void run() {
			while (true) {
				res.product("商品");

			}

		}

	}

	static class Consumer implements Runnable {

		private Resource res;

		Consumer(Resource res) {

			this.res = res;
		}

		public void run() {
			while (true) {
				res.consume();

			}

		}

	}

}

关于Lock类的更多使用方法大家可以参照JDK文档。

以上就是线程同步安全的内容。

时间: 2024-10-03 22:40:01

JAVA学习笔记之多线程专题(一):线程同步安全处理的相关文章

Java学习笔记之多线程

/* 进程: 正在进行中的程序(直译). 线程: 就是进程中一个负责程序执行的控制单元(执行路径) 一个进程中可以有多个执行路径, 称之为多线程. 一个进程中至少要有一个线程. 开启多个线程是为了同时运行多部分代码. 每一个线程都有自己运行的内容. 这个内容可以称为线程要执行的任务. 多线程的好处: 解决了多部分同时运行的问题. 多线程的弊端: 线程太多回到效率的降低. 其实应用程序的执行都是cpu在做着快速的切换完成的. 这个切换是随机的. jvm启动时就启动了多个线程,至少有两个线程可以分析

Java学习笔记-8.多线程编程

一.引入线程 1.多线程和多进程的区别 (1)两者粒度不同,进程是由操作系统来管理,而线程则是在一个进程内 (2)每个进程是操作系统分配资源和处理器调度的基本单位,拥有独立的代码.内部数据和状态 而一个进程内的多线程只是处理器调度的基本单位,共享该进程的资源,线程间有可能相互影响 (3)线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换的负担小 2.Thread类:Java的线程是通过java.lang.Thread类来实现,一个Thread对象代表一个线程

黑马程序员——JAVA学习笔记六(多线程)

1,    什么是多线程?一个程序可以执行多个任务,每一个任务称为一个线程,运行多个线程的程序称为多线程程序. 进程:正在进行中的程序(直译). 线程:进程中一个负责程序执行的控制单元(执行路径).   多线程的好处:解决了多部分代码同时运行的问题.多线程的弊端:线程太多,会导致效率的降低. 其实,多个应用程序同时执行都是CPU在做着快速的切换完成的.这个切换是随机的.CPU的切换是需要花费时间的,从而导致了效率的降低 2 ,    创建线程方式:  创建线程方式一:继承Thread类 1.定义

《深入Java虚拟机学习笔记》- 第20章 线程同步

1.对多线程的支持是Java语言的一大优势,Java对线程的控制主要集中在对线程的同步和协作上,Java使用的同步机制是监视器. 监视器 java监视器支持两种线程:互斥和协作.java虚拟机通过对象锁来实现互斥,允许多个线程在同一个共享数据上独立而不干扰地工作.协作则通过object类的wait方法和notify方法来实现,允许多个线程为了同一个目标而共同工作.我们将监视器比作一个建筑物,里面有很多房间,房间里面有一些数据,并且同一个时间只能被一个线程占据.一个线程进入房间到离开为止,独占其中

VB.net学习笔记(二十七)线程同步上

X夫妇二人试图同时从同一账户(总额1000)中支取1000.由于余额有1000,夫妇各自都满足条件,于是银行共支付2000.结果是银行亏了1000元.这种两个或更多线程试图在同一时刻访问同一资源来修改其状态,并产生不良后果的情况被称做竞争条件. 为避免竞争条件,需要使Withdraw()方法具有线程安全性,即在任一时刻只有一个线程可以访问到该方法. 一.线程同步 多个线程读或写同一资源,就会造成错漏状况,这时就需要线程同步.同步就是协同步调,按预定的先后次序进行运行.如:你说完,我再说.线程A与

Java学习笔记之多线程二

看到一篇讲线程的故事性文章,觉得很有意思,很佩服作者能这么生动地讲述出来,点击可跳转阅读此文章:<我是一个线程> 继续我的笔记中总结 - - 理解线程安全问题: 下面是书上看到的卖票例子:模拟3个窗口同时在售10张票. 上篇博文笔记总结了多线程创建的两种方式,那我们就分别以这两种实现多线程的方式来解决这个场景. 使用继承于Thread类的方式 上Demo: class SaleTicket extends Thread { int num = 10; // 票数 public SaleTick

2016年4月24日_JAVA学习笔记_多线程三_线程间通信

1.毕老师第十四天内容,线程间的通信.大概是使用wait(),notify()等一系列函数来控制各个线程的CPU执行资格和执行权,通过合适的时机在各个线程当中切换来达到线程间通信的目的. 涉及到的方法: wait():让线程处于等待状态,被wait()的线程会被存储到线程池当中,直到被唤醒.只能在同步方法中被调用. notify():随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态.只能在同步方法和同步代码块中被调用. notifyAll():接触所有在该对象上调用wait()方法的

java学习笔记14--多线程编程基础1

本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为一个进程,例如:用字处理软件编辑文稿时,同时打开mp3播放程序听音乐,这两个独立的程序在同时运行,称为两个进程 进程要占用相当一部分处理器时间和内存资源 进程具有独立的内存空间 通信很不方便,编程模型比较复杂 多线程 一个程序中多段代码同时并发执行,称为多线程,线程比进程开销小,协作和数据交换容易

线程异步学习(基于java学习笔记)

一 基本概念的理解 1.1线程中断方法 --interrupt() 当调用一个线程的interrupt方法时候,线程并没有真的被中断,只是对其状态改变,线程会有一个boolean变量isInterrputed.有wait sleep方法会阻塞线程. wait 和sleep方法都会使得线程挂起,阻塞.区别是wait会释放资源,而sleep方法并不会释放资源.一旦执行wait方法后,线程立即被挂起,直到有其他线程调用资源的notify方法.具体参见博客,多线程资源争用问题: http://blog.