`
lsx111
  • 浏览: 14251 次
  • 性别: Icon_minigender_1
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

线程中的资源共享和同步

阅读更多

<div class="iteye-blog-content-contain" style="font-size: 14px"></div>

 这个总结将对线程中的资源共享和线程同步问题进行简单的分析。

线程:是进程中的一个单一的连续控制流程。

一个进程可以含有多个线程,那下面就谈谈多线程。
java中多线程的实现有两种手段:1 继承Thread类  2实现Runnable接口
这里以买火车票为例。

class Ticket extends Thread {
	public int tickets = 10;
	public String name;
	public Ticket(String name){
		this.name = name;
	}
	public void run(){
		for(int i=0;i<10;i++){
			System.out.println(this.name+"买票"+this.tickets--);
		}
	}
}

public class Test1 {
	public static void main(String []arg){
		Ticket t1 = new Ticket("线程1");
		Ticket t2 = new Ticket("线程2");
		Ticket t3 = new Ticket("线程3");
		
		t1.run();
		t2.run();
		t3.run();
	}
}

 看到运行结果了吧,它们都是顺序执行的,这说明我们的调用方法不对,当我们把run方法改为start方法后才出现我们想要的结果.那我们来看看run方法和start方法的区别。

run()方法:在本线程内调用该Runnable对象的run()方法,可以重复多次调用;
start()方法:启动一个线程,调用该Runnable对象的run()方法,不能多次启动一个线程;

run()方法只是一个普通的方法,如果直接调用run方法的话那程序中还是只有一个主线程,并没有达到多线程的目的,主程序中还是会顺序执行,执行完一个run方法后才会继续执行下一个方法。而start()方法是负责启动一个线程,不用等待执行完其中的run方法后再执行下面的方法,而是直接执行下面的方法。简单的说就是你在run方法中写入要执行的代码,然后你只要调用start方法就可以了,至于什么时候执行run方法,那就不是你负责的了。start()方法的功能其实是向cpu申请另一个线程空间来执行run()方法的,它和当前的线程空间是相对独立的。就是说如果你直接调用run方法的话它仍然会执行,但是在当前的线程空间,所以它会按顺序执行,而调用start方法后,run方法就会和当前的代码并行的执行,从而达到多线程。

另一个我们要考虑的问题就是资源共享问题。这个问题也可以用来区别Thread和Runnable,而多线程在很多情况下都是处理资源共享的问题。下面我们仍以买火车票为例来看看资源共享的问题。

class Ticket extends Thread {
	public int tickets = 10;
	public String name;

	public void run() {
		while (this.tickets > 0) {
			System.out.println(this.name + " 卖票:" + this.tickets--);
		}
	}

	public Ticket(String name) {
		this.name = name;
	}
}

public class Test1 {
	public static void main(String[] arg) {
		Ticket t1 = new Ticket("线程1");
		Ticket t2 = new Ticket("线程2");
		Ticket t3 = new Ticket("线程3");

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

	}
}

 对于这个的运行结果我们之前已经试过了,从结果上看,它虽然实现了多线程,但它好像并不符合实际,我们定义一共有10张票,分三个地方来买,那就是说三个地方共享这10张票,可结果出现了30个数,显然是不对的,那如果把代码改一下:

class Ticket implements Runnable {
	public int tickets = 10;
	public String name;

	public void run() {
		while (this.tickets > 0) {
			System.out.println("卖票:" + this.tickets--);
		}
	}
}

public class Test1 {
	public static void main(String args[]) {
		// 准备四个售票点
		Demo d = new Demo();

		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		Thread t3 = new Thread(d);
		
		t1.start();
		t2.start();
		t3.start();
	}
}

 再运行,结果:

卖票:10
卖票:9
卖票:8
卖票:7
卖票:6
卖票:5
卖票:4
卖票:3
卖票:2
卖票:1

资源共享的问题也算是解决了。
还有一个问题就是线程同步的问题,这也是值得我们注意的问题,把上面的代码再进行修改:

class Demo implements Runnable {
	private int ticket = 10;

	public void run() {
		while (this.ticket > 0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("卖票:" + this.ticket--);
		}
	}
};

public class Test1 {
	public static void main(String args[]) {
		// 准备四个售票点
		Demo d = new Demo();

		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		Thread t3 = new Thread(d);
		
		t1.start();
		t2.start();
		t3.start();
	}
};

 运行结果:
卖票:10
卖票:9
卖票:8
卖票:7
卖票:6
卖票:5
卖票:4
卖票:3
卖票:2
卖票:1
卖票:0
卖票:-1

出现了两个不该出现的结果,那我们来分析一下出现这个结果的原因。
我们分三个售票点共同买10张票,当票数只剩一张的时候,假如被A拿走了,然后进入sleep中,而在这个时候,B也将最后一张票拿走了,而此时的tickets还等于1,当A把tickets放回的时候,tickets--变为了0,当B再放回的时候则出现了-1的情况。这就是不用步造成的。
那我们就要解决这个不同步的问题
下面介绍一下synchronized关键字:
    当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
    当两个并行的线程同时访问object的一个synchronized修饰的同步块是,同一时间只能有一个线程可以对其访问,只有当他访问完之后,另一个才能对其访问。
建立一个同步方法:

class Demo implements Runnable {
	private int ticket = 10;

	public synchronized void method(){
		while (this.ticket > 0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+" 卖票:" + this.ticket--);
		}
	}
	public void run() {
		method();
	}
};

public class Test1 {
	public static void main(String args[]) {
		// 准备四个售票点
		Demo d = new Demo();

		Thread t1 = new Thread(d,"a");
		Thread t2 = new Thread(d,"b");
		Thread t3 = new Thread(d,"c");
		
		t1.start();
		t2.start();
		t3.start();
	}
};

 运行结果:
b 卖票:10
b 卖票:9
b 卖票:8
b 卖票:7
b 卖票:6
b 卖票:5
b 卖票:4
b 卖票:3
b 卖票:2
b 卖票:1
这个结果虽然对票数同步了,但似乎又出现了其他的问题,一个售票点就把所有的票卖完了,回头看看我们的代码是哪里出了问题。
做如下改正:

class Demo implements Runnable {
	private int ticket = 10;

	public synchronized void method() {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " 卖票:"
					+ this.ticket--);
	}

	public void run() {
		while (this.ticket > 0) {
			method();
		}
	}
};

 运行结果:
a 卖票:10
a 卖票:9
a 卖票:8
a 卖票:7
a 卖票:6
a 卖票:5
c 卖票:4
c 卖票:3
b 卖票:2
b 卖票:1
c 卖票:0
a 卖票:-1
又出问题了(无奈),看看又是什么情况,我们在同步方法中加一个if(this.tickets>0)保护,在运行,看看结果吧... ...终于没问题了。

分享到:
评论

相关推荐

    多线程不同步读写共享资源代码

    多线程不同步读写共享资源 文章配套代码 我在很早的时候就听说多线程不同步是可以读写共享资源的。这听起来感觉挺好,因为一旦同步线程,将在同步线程上花去一定的CPU时间片. 这一切都是真的,但是,不同步线程的...

    vc++中的线程锁(线程锁保持线程同步)

    在VC++编程环境中,线程同步是一个至关重要的概念,特别是在多线程程序设计中,以确保并发执行的线程能够安全地访问共享资源,避免数据竞争和其他潜在的问题。本篇文章将详细探讨线程锁在VC++中的应用,以及如何通过...

    Java分布式应用学习笔记03JVM对线程的资源同步和交互机制

    ### Java分布式应用学习笔记03:JVM对线程的资源同步和交互机制 在深入探讨Java虚拟机(JVM)如何处理线程间的资源同步与交互机制之前,我们先来明确几个关键概念:线程、多线程、同步、并发以及它们在Java中的实现...

    NET中多线程间资源共享与访问

    本文档深入探讨了.NET平台上的多线程资源共享与访问机制,并详细介绍了一个自定义类`ThreadLockHelper`,该类能有效地管理线程间的资源访问,简化高级程序员处理多线程问题的过程。 #### 访问共享资源的概念 在多...

    解决多线程编程中的同步互斥问题

    使用关键段可以有效地解决多线程编程中的同步互斥问题,确保了在多线程环境中对共享资源的安全访问。但是需要注意的是,关键段仅能解决单个CPU核心上的互斥访问问题,对于多处理器或多核心环境下的同步问题可能需要...

    java 线程同步 信号量控制同步

    线程同步是 Java 编程中的一种机制,用于控制多个线程之间的资源访问顺序,以避免线程之间的冲突和数据不一致。线程同步的目的就是避免线程“同步”执行,即让多个线程之间排队操作共享资源。 关于线程同步,需要...

    多线程资源共享集合

    在实际应用中,多线程资源共享可能会涉及到线程同步和通信的各种技术,如`wait()`, `notify()`, `notifyAll()`,以及高级的`java.util.concurrent`包中的工具类,如`Semaphore`, `CyclicBarrier`, `CountDownLatch`...

    C#代码_线程同步线程同步线程同步线程同步线程同步线程同步

    在编程领域,线程同步是多线程编程中的一个核心概念,它确保多个线程在访问共享资源时能正确地协调执行,防止数据竞争和不一致的状态。在C#中,线程同步可以通过多种机制来实现,其中包括信号量(Semaphore)和加锁...

    3种多线程实现同步方法

    然而,多线程也带来了数据同步的问题,因为多个线程可能同时访问共享资源,如果不加以控制,就可能导致数据不一致或引发错误。本篇文章将深入探讨三种在C++中实现多线程同步的方法:事件对象、关键代码段和互斥对象...

    linux上实现多进程和多线程实现同步互斥(源代码)

    多线程则是在一个进程中创建多个执行流,它们共享同一块内存空间,资源利用率高,但数据同步和互斥问题更复杂。在Linux中,可以使用`pthread_create()`创建线程,`pthread_join()`等待线程结束。线程间的同步互斥...

    MFC中的多线程同步

    一个典型的用法可能包括创建一个CMutex对象,然后在线程中使用`Lock()`和`Unlock()`方法来控制对共享资源的访问。如果有多个线程尝试同时访问,只有一个会成功获取锁,其余的将被阻塞直到锁被释放。 通过深入研究和...

    线程与内核对象的同步

    理解这些对象及其工作原理对于编写多线程应用程序至关重要,特别是在处理并发和资源共享时,能有效防止死锁和竞态条件的发生。 总之,线程与内核对象的同步是Windows编程中不可或缺的一部分,通过合理利用内核对象...

    delphi中线程同步问题

    在 Delphi 中,多线程编程常常涉及到线程同步,以确保多个线程安全地访问共享资源或执行特定操作。`Synchronize` 方法是 Delphi 中用于在主线程中安全执行代码的一种机制,尤其适用于 UI 更新。然而,在 DLL 或 ...

    线程同步的四种方式

    在多线程编程中,线程同步是一种控制多个线程并发执行时访问共享资源的方式,以避免数据不一致和死锁等问题。以下是对线程同步的四种主要方式的详细解释: 1. **事件(Event)** 事件是Windows API提供的一种线程...

    多线程的批量线程同步解决方案

    线程同步是多线程编程中的重要概念,用于控制不同线程间的执行顺序和访问共享资源的方式,防止竞态条件和死锁的发生。常见的线程同步机制包括: 1. **互斥量(Mutex)**:一种简单的同步机制,一次只有一个线程能获取...

    线程同步小例子

    在编程领域,线程同步是多线程编程中的一个核心概念,它涉及到如何有效地管理和协调多个并发执行的线程,确保它们能正确地共享资源,避免数据竞争和死锁等问题。这个“线程同步小例子”是基于孙鑫先生著作中的示例...

    IOS线程管理,线程同步

    在iOS开发中,线程管理是一项至关重要的技能,它关系到应用的性能和用户体验。本文将深入探讨iOS线程管理,特别是线程的创建和线程同步,这些都是开发者需要掌握的基本知识。 首先,我们来理解一下线程的概念。线程...

Global site tag (gtag.js) - Google Analytics