`
aijuans
  • 浏览: 1567835 次
社区版块
存档分类
最新评论

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

 
阅读更多

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

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

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

2.适合资源的共享.

 

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

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

package org.dennist.thread.demo;
/**
 *
 *  TicketThread.java    
 *
 *  @version : 1.1
 *  
 *  @author  : 苏若年    <a href="mailto:DennisIT@163.com">发送邮件</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张票,线程之间没有进行资源共享

<!--EndFragment-->

实现Runnable的售票线程

<!--EndFragment-->

package org.dennist.thread.demo;
/**
 *
 *  TicketThreadR.java    
 *
 *  @version : 1.1
 *  
 *  @author  : 苏若年    <a href="mailto:DennisIT@163.com">发送邮件</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:DennisIT@163.com">发送邮件</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中方法:

JAVA多线程同步主要依赖于若干方法和关键字
1  wait方法

2  notify方法和notifyAll方法

3  synchronized关键字

4 atomic action(原子操作)

详细说明见:[http://www.cnblogs.com/dennisit/archive/2013/02/25/2931573.html]

此处针对上面情况使用同步关键字synchronized解决.同步关键字使用有2种方法

1.同步代码块

2.同步方法

<!--EndFragment-->

同步代码块

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

<!--EndFragment--> synchronized(对象){   //一般都是讲this锁定

         //锁定对象

     }

<!--EndFragment-->上面的问题使用同步代码块解决

package org.dennist.thread.demo;
/**
 *
 *  TicketThreadR.java    
 *
 *  @version : 1.1
 *  
 *  @author  : 苏若年    <a href="mailto:DennisIT@163.com">发送邮件</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:DennisIT@163.com">发送邮件</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]

<!--EndFragment-->

在线交谈

分享到:
评论

相关推荐

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

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

    VB 实现多线程

    通过本文,我们详细介绍了如何在VB中利用`CreateThread`函数实现多线程,并解决了常见的退出时内存访问异常问题。虽然VB在多线程支持方面不如一些现代语言那样完善,但通过合理的设计和使用API,仍然可以构建出高...

    C++多线程学习

    并发执行的线程可能会访问共享资源,这可能导致数据竞争问题,即两个或更多线程同时修改同一数据。为了解决这个问题,C++提供了互斥量(mutex)来确保一次只有一个线程能访问特定的资源。`std::mutex`是C++标准库中...

    Java多线程的总结

    在多线程环境下,数据共享可能会引发数据不一致的问题。Java提供了多种同步机制,如synchronized关键字、volatile变量、Lock接口(ReentrantLock、ReadWriteLock等)和Semaphore信号量。synchronized提供互斥访问,...

    Java 多线程学习总结归纳(附代码)

    下面是对Java多线程学习的详细解析。 1. **多线程概述**: 多线程是指一个程序内可以同时执行多个独立的执行流,每个执行流被称为一个线程。Java通过Thread类来代表线程,每个线程都有自己的生命周期,包括新建、...

    Java 多线程学习总结6

    在“Java多线程学习总结6”这个主题中,我们可以深入探讨Java多线程的实现、管理及优化。下面将详细阐述相关知识点。 1. **线程的创建方式** - **继承Thread类**:自定义类继承Thread类,并重写run()方法,创建...

    corejava多线程学习总结.pdf

    ### CoreJava多线程学习总结 #### 一、基本概念 多线程是现代软件开发中非常重要的一个概念,尤其在Java这样的高级编程语言中,它使得程序能够更高效地利用计算机资源,实现并发处理任务。为了更好地理解CoreJava...

    自己总结的多线程

    本文从多线程的基础概念出发,深入探讨了Java中多线程的实现机制及线程安全问题,并介绍了几种常见的设计模式(包括单例模式、工厂模式和适配器模式),这些模式有助于解决多线程环境下的常见问题。通过对这些知识点...

    多线程两种实现方式Java

    总结,理解并熟练掌握Java中的多线程实现方式是提升程序性能和编写高效并发代码的基础。无论你是通过继承`Thread`还是实现`Runnable`,都需要对线程同步和通信有深入的理解,以便在实际项目中解决并发问题。通过实践...

    Linux 多线程实现生产者消费者模式.pdf

    总结来说,Linux多线程实现生产者消费者模式涵盖了多线程创建、线程同步与互斥、锁机制、条件变量以及线程屏障等核心知识点。这些知识点是Linux下进行高级多线程编程不可或缺的部分,对于理解现代操作系统中多任务...

    java多线程应用实现示例

    在多线程环境中,数据共享和资源竞争可能导致问题,如死锁、活锁和饥饿。Java提供了多种同步机制,如synchronized关键字、wait()、notify()和notifyAll()方法,用于控制线程间的交互。在小球运动示例中,可能涉及到...

    关于C# 多线程学习

    总结来说,C#中的多线程学习涉及到了线程的创建、控制和管理等多个方面,掌握这些基本概念对于开发高效、稳定的多线程应用程序至关重要。然而,需要注意的是,线程的管理并非没有挑战,不当的操作可能会导致程序出现...

    多线程实现人脸快速循环比对

    总结来说,“多线程实现人脸快速循环比对”项目融合了深度学习人脸识别技术、Windows编程框架MFC以及多线程并发处理。通过巧妙地结合这些技术,可以实现快速、精准的人脸比对,尤其适用于处理大量图片的场景。理解并...

    多线程实现多控制两个案例

    本篇文章将详细讲解如何通过多线程实现对两个任务的独立控制,以及如何进行线程同步,以确保数据的一致性。 首先,我们来看第一个案例:实现两个线程分别控制两个运动。在计算机编程中,线程可以被视为程序的执行流...

    java多线程学习资料

    ### Java多线程学习资料知识点解析 #### 一、引言 Java作为一种广泛使用的编程语言,在并发编程领域具有独特的优势。多线程是Java中实现并发处理的核心技术之一,能够显著提升程序的性能和响应性。本文将深入探讨...

    多线程基础个人总结思维导图

    在IT行业中,多线程是程序并发执行的一种方式,它极大地提高了系统资源的利用率和程序...在学习过程中,可以参考"多线程基础总结01.bmp"和"多线程基础总结01.mmap"等文件,它们可能提供了更为详细和直观的结构化知识。

    Java线程学习和总结

    本文档("Java线程学习和总结.htm")可能包含了更多关于线程的实例、源码分析和常见问题解决方案,你可以通过阅读来进一步加深对Java线程的理解。同时,"Java线程学习和总结.files"目录下的文件可能是与文章相关的...

    C#多线程学习,学习多线程好资料。

    ### C#多线程学习详解 #### 一、多线程的基本概念 ##### 1. 什么是进程? 进程是程序的一次动态执行过程,它包含了正在运行的程序所需的内存、系统资源以及执行上下文。简单来说,当你启动一个程序时,操作系统会...

    Linux系统下的多线程编程入门.pdf

    总结,Linux系统的多线程编程为开发者提供了强大的并发能力,但也带来了挑战。理解和掌握线程创建、同步、通信和问题处理,是编写高效、可靠的多线程程序的基础。通过不断实践和学习,我们可以驾驭这一强大的工具,...

Global site tag (gtag.js) - Google Analytics