多线程实现资源共享的问题学习与总结

标签: 多线程 资源 共享 | 发表时间:2013-02-24 22:46 | 作者:苏若年
出处:http://www.cnblogs.com/

我么知道Java传统多线程的实现有两种方法,继承Thread类或者实现Runnable即可.线程启动时调用start()方法.

实现Runnable接口相比继承Thread类有如下好处:

1.避免单继承的局限,一个类可以同时实现多个接口

2.适合资源的共享.

 

实现多线程模拟售票点卖票来说明实现Runnable即可可以达到资源共享的目的.

使用继承Thread类的多线程售票实现

package org.dennist.thread.demo;
/**
*
* TicketThread.java
*
* @version : 1.1
*
* @author : 苏若年 <a href="mailto:[email protected]">发送邮件</a>
*
* @since : 1.0 创建时间: 2013-2-24 下午02:22:49
*
* TODO : class TicketThread.java is used for ...
*
*/
public class TicketThreadT extends Thread{

private int num = 5; //总共票数设定为5张

@Override
public void run() {
for(int i=0; i<10; i++){
if(this.num>0){ //打印买票信息
System.out.println(Thread.currentThread().getName() + "买票: " + this.num--);
}
}
}

public static void main(String[] args) {
TicketThreadT th1 = new TicketThreadT(); //线程一
th1.setName("售票口一");
TicketThreadT th2 = new TicketThreadT(); //线程二
th2.setName("售票口二");
TicketThreadT th3 = new TicketThreadT(); //线程三
th3.setName("售票口三");

//分别启动三个线程
th1.start();
th2.start();
th3.start();
}
}

程序运行结果:

总共5张票,启动了三个线程,从打印结果可以看出,一共卖出去了15张票,线程之间没有进行资源共享

实现Runnable的售票线程

package org.dennist.thread.demo;
/**
*
* TicketThreadR.java
*
* @version : 1.1
*
* @author : 苏若年 <a href="mailto:[email protected]">发送邮件</a>
*
* @since : 1.0 创建时间: 2013-2-24 下午02:29:23
*
* TODO : class TicketThreadR.java is used for ...
*
*/
public class TicketThreadR implements Runnable{

private int num = 5; //总共票数设定为5张

@Override
public void run() {
for(int i=0; i<10; i++){
if(this.num>0){ //打印买票信息
System.out.println(Thread.currentThread().getName() + "买票: " + this.num--);
}
}
}

public static void main(String[] args) {
TicketThreadR ticketThread = new TicketThreadR();

Thread th1 = new Thread(ticketThread); //线程一
th1.setName("售票口一");
Thread th2 = new Thread(ticketThread); //线程二
th2.setName("售票口二");
Thread th3 = new Thread(ticketThread); //线程三
th3.setName("售票口三");

th1.start();
th2.start();
th3.start();
}
}

程序运行结果

虽然现在程序中有三个线程,但是三个线程总共卖出了5张票,也就是说使用Runnable实现的多线程可以达到资源共享的目的.

Java多线程访问共享方式

(1)如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做。

(2)如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,有如下两种方式来实现这些Runnable对象之间的数据共享:

  1、将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。

  2、将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。

  3、上面两种方式的组合:将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部变量,每个线程的Runnable对象作为外部类中的成员内部类或局部内部类。

  4、总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥和通信。

(3)极端且简单的方式,即在任意一个类中定义一个static的变量,这将被所有线程共享。

 

 

在Thread类中存在以下的几个方法可以设置和取得名字.

设置名字: public final void setName(String name) 

public Thread(Runnable target, String name)

public Thread(String name)

取得名字: public final String getName()

在线程的操作中因为其操作的不确定性,所以提供了一个方法,可以取得当前的操作线程.

public static Thread currentThread()

说明:

对于线程的名字一般是在启动前进行设置,最好不要设置相同的名字,最好不要为一个线程改名字.

在Java执行中一个Java程序至少启动2个线程:一个主线程和一个垃圾回收线程.

 

多线程的同步问题

上面的实现Runnable程序就真的没问题了吗?我们知道现实生活中买票总会有等待,跟延迟,那么我们模拟现实生活中的买票然后再来看上面的程序输出.

package org.dennist.thread.demo;
/**
*
* TicketThreadR.java
*
* @version : 1.1
*
* @author : 苏若年 <a href="mailto:[email protected]">发送邮件</a>
*
* @since : 1.0 创建时间: 2013-2-24 下午02:29:23
*
* TODO : class TicketThreadR.java is used for ...
*
*/
public class TicketThreadR implements Runnable{

private int num = 5; //总共票数设定为5张

@Override
public void run() {
for(int i=0; i<10; i++){
try {
Thread.sleep(200); //休息200毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
if(this.num>0){ //打印买票信息
System.out.println(Thread.currentThread().getName() + "买票: " + this.num--);
}
}
}

public static void main(String[] args) {
TicketThreadR ticketThread = new TicketThreadR();

Thread th1 = new Thread(ticketThread); //线程一
th1.setName("售票口一");
Thread th2 = new Thread(ticketThread); //线程二
th2.setName("售票口二");
Thread th3 = new Thread(ticketThread); //线程三
th3.setName("售票口三");

th1.start();
th2.start();
th3.start();
}
}

 

如果想解决这样的问题,就必须使用同步,所谓的同步就是指多个操作在同一个时间段内只有一个线程进行,其他线程要等待此线程完成之后才可以继续执行.

可以通过同步代码的方法进行代码的加锁操作,同步的实现有2中方法:

1.同步代码块

2.同步方法

同步代码块

使用synchronized关键字进行同步代码块的声明,但是在使用此操作时必须明确的指出到底要锁定的是哪个对象,一般是以当前对象为主.

  synchronized(对象){   //一般都是讲this锁定

         //锁定对象

     }

上面的问题使用同步代码块解决

package org.dennist.thread.demo;
/**
*
* TicketThreadR.java
*
* @version : 1.1
*
* @author : 苏若年 <a href="mailto:[email protected]">发送邮件</a>
*
* @since : 1.0 创建时间: 2013-2-24 下午02:29:23
*
* TODO : class TicketThreadR.java is used for ...
*
*/
public class TicketThreadR implements Runnable{

private int num = 5; //总共票数设定为5张

@Override
public void run() {
for(int i=0; i<10; i++){
//使用同步代码块
synchronized (this) {
try {
Thread.sleep(300); //休息300毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
if(this.num>0){
//打印买票信息
System.out.println(Thread.currentThread().getName() + "买票: " + this.num--);
}
}

}
}

public static void main(String[] args) {
TicketThreadR ticketThread = new TicketThreadR();

new Thread(ticketThread,"售票口一").start(); //线程一
new Thread(ticketThread,"售票口二").start(); //线程二
new Thread(ticketThread,"售票口三").start(); //线程三
}
}

 

同步方法

同步方法是在方法上增加synchronized关键字修饰
上面的问题使用同步代码块解决

package org.dennist.thread.demo;
/**
*
* TicketThreadR.java
*
* @version : 1.1
*
* @author : 苏若年 <a href="mailto:[email protected]">发送邮件</a>
*
* @since : 1.0 创建时间: 2013-2-24 下午02:29:23
*
* TODO : class TicketThreadR.java is used for ...
*
*/
public class TicketThreadR implements Runnable{

private int num = 5; //总共票数设定为5张

@Override
public void run() {
for(int i=0; i<10; i++){
sale(); //调用同步方法
}
}

//使用同步方法
public synchronized void sale(){
try {
Thread.sleep(300); //休息300毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
if(this.num>0){
//打印买票信息
System.out.println(Thread.currentThread().getName() + "买票: " + this.num--);
}
}

public static void main(String[] args) {
TicketThreadR ticketThread = new TicketThreadR();

new Thread(ticketThread,"售票口一").start(); //线程一
new Thread(ticketThread,"售票口二").start(); //线程一
new Thread(ticketThread,"售票口三").start(); //线程一
}
}

 

多个线程共享同一资源的时候需要进行同步,但是过多的同步会造成死锁.

 

什么叫死锁?死锁产生的主要原因是什么?死锁产生的必要条件,如何解决死锁?​

死锁指在多道程序系统中,一组进程中的每一个进程均无限期的等待该被改组进程中的另一个进程所以占有且永远不会释放的资源,这种现象称为系统处于死锁状态.​

死锁产生的原因主要有2个:​

  1.竞争资源,系统提供的资源数量有限,不能满足每个进程的要求​

  2.多道程序运行时,.进程推进顺序不合理​

产生死锁的必要条件​

  1.互斥使用资源​

  2.占用并等待资源​

  3.不可抢夺资源​

  4.循环等待资源​

解决死锁的方法​

  1.预防死锁:破坏死锁产生的条件(除过互斥条件,因为破坏互斥条件不现实)​

  2.避免死锁​

  3.检测与排除​

  4.置之不理​

 

转载请注明出处:[ http://www.cnblogs.com/dennisit/archive/2013/02/24/2925288.html]

本文链接

相关 [多线程 资源 共享] 推荐:

多线程实现资源共享的问题学习与总结

- - 博客园_首页
我么知道Java传统多线程的实现有两种方法,继承Thread类或者实现Runnable即可.线程启动时调用start()方法.. 实现Runnable接口相比继承Thread类有如下好处:. 1.避免单继承的局限,一个类可以同时实现多个接口. 实现多线程模拟售票点卖票来说明实现Runnable即可可以达到资源共享的目的..

多线程中共享对象的可见性

- - ITeye博客
在阅读《java并发编程实战》的第三章的时候,看到书中的一个例子,随在Eclipse中执行看看效果. 书中的解释是,这个程序的执行结果除了打印出42以外,还有两外另种情况:一时无限循环下去,二是打印出0来. 其中打印42很好理解,因为,在启动ReaderThread线程以后,如果还没有设置ready为true,那么ReaderThread会一直循环,直到读取ready的值为true,然后打印出结果42来.

利用jsoup爬取百度网盘资源分享连接(多线程)

- - CSDN博客推荐文章
       突然有一天就想说能不能用某种方法把百度网盘上分享的资源连接抓取下来,于是就动手了. 知乎上有人说过最好的方法就是http://pan.baidu.com/wap抓取,一看果然链接后面的uk值是一串数字,就想到可以自己拼装链接,循环不断的去抽取页面. 于是自己分析了下页面结构,就开始了.

10种方式实现跨域资源的共享

- way - 互联网的那点事
在客户端编程语言中,如JavaScript和ActionScript,同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义. 同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法. 那么什么叫相同域,什么叫不同的域呢. 当两个域具有相同的协议(如http), 相同的端口(如80),相同的host(如www.example.org),那么我们就可以认为它们是相同的域.

北京森林工作室汉语句义结构标注语料库(BFS-CTC)共享资源

- - 我爱自然语言处理
句义结构分析是汉语语义分析中不可逾越的重要环节,为了满足汉语句义结构分析的需要,北京森林工作室(BFS)基于现代汉语语义学理论构建了一种层次化的汉语句义结构模型,定义了标注规范和标记形式,建设了一个汉语句义结构标注语料库BFS-CTC(Beijing Forest Studio – Chinese Tagged Corpus).

Java Thread多线程

- - CSDN博客推荐文章
Java Thread多线程. Java 多线程例子1 小例子. super("zhuyong");//设置线程的名字,默认为“TestThread”. Java 多线程例子2 前台线程(用户线程) 后台线程(守护线程 ). 1,setDaemon(true)后就是后台线程(守护线程 ),反之就是前台线程(用户线程).

实践与共享:体态轻盈、功能强大的网站资源备份、离线浏览工具Teleport Pro + 有效激活码

- yasy - 翱翔
         Teleport Pro是一款体态轻盈、功能强大的离线浏览器. 通过超级简单操作(指定对象和下载深度),即可把一个站点(当然包括博客)的全部或部分文章,以及该站点中的特定内容(网站目录、文章内容、图片影像、背景音乐),原汁原味地下载到计算机的硬盘之中,从而非常容易地实现离线浏览. 为了方便光临本博网友的使用,以下提供了官方英文原版和“汉化版”两种下载,并提供了有效激活码——.

共享成本

- wooden - 不许联想
如果再谈论什么音乐版权,主张听唱片不要听MP3,就会显得有些傻逼了. 之前我只要在博客上说,就会有一帮共享主义的捍卫者跳出来跟我理论. 甚至,IT界的人认为版权的概念该改改了——你直接说不该有版权不就完了,改个毛啊. 怎么改它都是一种权利,除非你消灭这种权利. 但我现在在思考这样一个问题,它是一个哲学问题,不是版权问题.