`
lsx111
  • 浏览: 13642 次
  • 性别: 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时间片. 这一切都是真的,但是,不同步线程的...

    如何用 VB.net同步对共享资源在多线程环境中访问

    如何用 Visual Basic.net 或 Visual Basic 2005 同步对共享资源在多线程环境中访问

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

    在linux上分别用多进程和多线程实现的同步互斥操作(源代码)

    Linux 线程间同步机制

    互斥锁是一个二元变量,其状态为开锁(允许0)和上锁(禁止1),将某个共享资源与某个特定互斥锁绑定后,对该共享资源的访问如下操作: (1)在访问该资源前,首先申请该互斥锁,如果该互斥处于开锁状态,则申请到该...

    Linux系统编程之线程同步

    资源共享(独享资源则不会) 2. 调度随机(意味着数据访问会出现竞争) 3. 线程间缺乏必要的同步机制。 以上3点中,前两点不能改变,欲提高效率,传递数据,资源必须共享。只要共享资源,就一定会出现竞争。只要...

    线程同步方法,和线程创建方法

    线程隶属于进程,线程是属于进程内部的程序流,目前主流的操作系统都支持多进程,而... 而线程是轻量级的,新建线程会共享所在进程的内存资源等,因此线程对系统资源的消耗 比较小,当然每个线程都拥有一块独立的栈区;

    linux之线程同步一.doc

    在Linux中,线程同步是一种控制多个线程之间交互的方式,以确保它们按照预期的顺序执行和避免数据竞争。线程同步在多线程编程中非常重要,因为它可以确保各个线程之间的数据安全和正确性。 以下是Linux中常见的线程...

    linux线程同步.pdf

    在多线程程序中,线程同步是确保线程安全的关键。线程安全意味着当多个线程访问共享资源时,程序的行为是可预测的,不会出现不一致或错误的结果。线程同步可以防止数据竞争、避免死锁和饥饿等问题。数据竞争是指两个...

    实验4 线程编程实验.doc

    一个进程可以由多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。 2. 线程的创建方法 在Java中,线程可以通过继承Thread...

    多线程不同步演示2

    多线程不同步演示2,一个线程写数据,另一个线程读取数据,在没有同步的情况下,会出现什么问题?若你不知道,你可以看看该源码。

    [Java]多线程:共享资源同步——不认真看你会后悔的

    共享资源同步 在进行多线程开发时最令人头痛的问题估计就是对共享资源的控制了吧,今天就让我们谈一谈这个问题吧。 共享资源顾名思义就是需要被多个线程使用的资源,但是很多情况下我们是不能允许多个线程同时使用这...

    java应用程序中使用线程

    3.1 Java线程 3.2 创建线程 3.3 使用线程的缺点 3.3.1 初始启动变慢 3.3.2 资源利用 3.3.2 资源利用 3.4 线程管理 3.5 共享资源的使用同步 3.5.1 同步方法和同步代码块的嵌套调用...

    多线程编程中关键的一步是保护所有的共享资源,

    多线程编程中关键的一步是保护所有的共享资源,工具主要有互锁函数、临界段和互斥体等;另一个实质性部分是协调线程使其完成应用程序的任务,为此,可利用内核中的事件对象和信号。 在进程内或进程间实现线程同步的...

    java synchronize 线程同步

    当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。

    操作系统中对于线程的同步与互斥问题的设计原理及代码

    线程间的互斥:并发执行的线程共享某些类临界资源,对临界资源的访问应当采取互斥的机制。 线程间的同步:并发执行的线程间通常存在相互制约的关系,线程必须遵循一定的规则来执行,同步机制可以协调相互制约的关系...

    多线程同步(多线程如何访问临界区资源)

    该demo展示了多线程使用临界区访问共享资源,并与不使用临界区对共享资源 访问做对比;并展示了多种开启线程(AfxBeginThread、_beginthreadex)的 方式

    linux之线程同步的概要介绍与分析

    在Linux操作系统中,线程同步是多线程编程中的一个核心概念,它确保了多个线程在访问共享资源时的正确性与一致性,避免了诸如数据竞争和竞态条件等问题。为了实现这一目标,Linux提供了一系列强大的线程同步机制和...

    线程同步的四种详细使用方法--临界区、互斥量、事件等

    线程同步是指在多线程程序中,为了避免线程之间的数据混淆和资源竞争,通过某种机制来控制线程的执行顺序和访问共享资源的方式。线程同步技术是计算机软件开发的重要技术,多线程同步技术的原理和实现对软件开发人员...

    Delphi多线程编程之三 同步读写全局数据

    三、还有一种用信号量对象来管理线程同步的,它是在互斥的基础上建立的,但信号量增加了资源计数的功能,预定数目的线程允许同时进入要同步的代码。有点复杂,想不到在哪可以用,现在就不研究论了。 unit Tst_...

Global site tag (gtag.js) - Google Analytics