`
jieke_ZJ
  • 浏览: 44828 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

java多线程并发及线程池

 
阅读更多

1、继承Thread类创建线程类

public class FirstThreadTest extends Thread {
    public void run(){
        System.out.println("这里是线程的执行方法");
    }

    public static void main(String[] args) {
        //获得线程
        FirstThreadTest thread = new FirstThreadTest();
        System.out.println("线程名称为:"+thread.getName());
        //启动线程
        thread.start();
        System.out.println("main方法也是一个线程:"+Thread.currentThread().getName());
    }
}

执行结果:

线程名称为:Thread-0
main方法也是一个线程:main
这里是线程的执行方法

2、通过Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体;
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;
(3)调用线程对象的start()方法来启动该线程。

public class RunnableThreadTest implements Runnable {

    public void run() {
        System.out.println("这里是线程方法");
        System.out.println("线程名为:" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        System.out.println("main方法线程:" + Thread.currentThread().getName());
        RunnableThreadTest rtt = new RunnableThreadTest();
        new Thread(rtt, "新线程1").start();
        new Thread(rtt, "新线程2").start();
    }

}

执行结果

main方法线程:main
这里是线程方法
线程名为:新线程1
这里是线程方法
线程名为:新线程2

两种线程创建的具体区别:http://www.cnblogs.com/whgw/archive/2011/10/03/2198506.html(扩展性和资源共享性)

多线程并发

多线程并发出现问题主要涉及到两个方面:多线程共享数据同步问题和数据因并发产生不一致问题;

1、多线程共享数据同步问题
如下代码:

/**
 * 两个工人一起搬砖
 */
public class Banzhuan {
    public static void main(String[] args) {
        // 一个工厂
        Factory factory = new Factory();
         /**
           * p1线程和p2线程都是由factory这个实例创建的
           * 那么p1调用外部类的getZhuanTou()方法就相当于调用的是factory这个实例的getZhuanTou(),同样的,p2调用的也是factory这个实例的getZhuanTou().
           * 那么这里就出现了两个线程同时访问factory的getZhuanTou()方法。
           * 而factory的getZhuanTou()方法又对zhuanTou这个属性进行了zhuanTou--操作。
           * 换句话说,两个线程同时访问了factory的数据zhuanTou.这时候就可能产生线程安全问题。
           */
        // 同一个工厂的两个工人
        Person p1 = factory.getPerson();
        Person p2 = factory.getPerson();
        p1.start();
        p2.start();
    }
}

// 工厂
class Factory {
    int zhuanTou = 20;// 一共20块砖头

    public int getZhuanTou() {
        if (zhuanTou == 0) {
            throw new RuntimeException(Thread.currentThread().getName()+ ",没有砖头搬了!");
        }
        Thread.yield();
        return zhuanTou--;

    }

    // 工人
    class Person extends Thread {
        // 不停的搬砖
        public void run() {
            while (true) {
                // 获取线程名(工人名) 及 剩下砖头数
                System.out.println(getName() + "搬了第" + getZhuanTou() + "块砖头");
                // 当线程的run方法中出现了异常,且我们没有 解决,那么该线程终止并死亡。但不会影响 当前进程中的其他线程。
                Thread.yield();
            }
        }
    }

    // 获取工人
    public Person getPerson() {
        return new Person();
    }
}

多次运行结果:
这里写图片描述

这里并不是每次都会出错,要多运行几次,就会可能碰到多种错误,比如搬到了同一块砖,比如少搬一块砖,比如搬完到了0然后还有继续搬……
原因是:比如现在还剩15块砖头,工人p1搬第15块砖头的时候正拿到手上,但是还没有登记减少一块砖头(即还没有运行zhuanTou–),这个时候工人p2也去拿砖,然后登记的时候一看还剩15块砖头,实际呢只剩14块了……
解决方法:
synchronized:当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
所以将getZhuanTou()方法改成如下就可以了

public int getZhuanTou() {
        synchronized (this) {
            if (zhuanTou == 0) {
                throw new RuntimeException(Thread.currentThread().getName()+",没有砖头搬了!");
            }
            Thread.yield();
            return zhuanTou--;
        }
    }

为啥不将这个关键词锁在方法那呢?尽量将锁在范围最小的地方,这样运行的效率更快。

2、数据因并发产生不一致问题
参考:https://my.oschina.net/clopopo/blog/149368

ThreadLocal:为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象。

首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象;

另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。

再次,注意每一个线程都保存一个对象的时候(非基本类型数据)应该是new一个新对象而不是引用一个对象,如下:

private static ThreadLocal<Index> local = new ThreadLocal<Index>() {
        @Override
        protected Index initialValue() {
            return new Index(); //注意这里
        }
    };

案例代码:

public class ThreadLocalTest {

        //创建一个Integer型的线程本地变量
    public static final ThreadLocal<Integer> local = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };
    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[5];
        for (int j = 0; j < 5; j++) {       
               threads[j] = new Thread(new Runnable() {
                @Override
                public void run() {
                                        //获取当前线程的本地变量,然后累加5次
                    int num = local.get();
                    for (int i = 0; i < 5; i++) {
                        num++;
                    }
                                        //重新设置累加后的本地变量
                    local.set(num);
                    System.out.println(Thread.currentThread().getName() + " : "+ local.get());

                }
            }, "Thread-" + j);
        }

        for (Thread thread : threads) {
            thread.start();
        }
    }
}

运行结果:
Thread-0 : 5
Thread-4 : 5
Thread-2 : 5
Thread-1 : 5
Thread-3 : 5

--------------------------------------------------------------------------------------------------

3、总结:
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别:
1、synchronized关键字主要解决多线程共享数据同步问题,ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题;
2、synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享;
synchronized和ThreadLocal比较:http://blog.csdn.net/huyongl1989/article/details/8088841

线程池

当有许多请求需要去处理的时候,如果只是单独的一个人去处理,可想而知那会让后面在排队的人等多久,这样就需要线程池,有请求过来了就到线程池里面取出一条线程去处理它,处理完成就把它收回到线程池里面,然而自己实现 一个功能强大的线程池也并非易事,在java1.5之后专门提供了线程池的类库。

Java通过Executors接口提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程;
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待;
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行;
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行;
下面简单看一下newFixedThreadPool这种线程池:

public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            fixedThreadPool.submit(new Runnable() {
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName()+"---->"+index);
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

运行:
pool-1-thread-1—->0
pool-1-thread-3—->2
pool-1-thread-2—->1
pool-1-thread-3—->3
pool-1-thread-2—->5
pool-1-thread-1—->4
pool-1-thread-3—->6
pool-1-thread-1—->8
pool-1-thread-2—->7
pool-1-thread-3—->9

因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
fixedThreadPool.submit(Runnable task)或者execute方法会调用线程的run方法;

 

线程池参考地址:http://blog.csdn.net/u012385190/article/details/52486393

分享到:
评论

相关推荐

    java多线程、并发及线程池介绍收藏的几篇文档

    Java多线程、并发以及线程池是Java编程中至关重要的概念,特别是在处理高并发、高性能的系统设计时。以下是对这些主题的详细说明: 1. **Java 程序中的多线程** - 多线程允许一个程序同时执行多个任务,提高程序...

    Java 模拟线程并发

    Java 模拟线程并发是编程领域中的一个重要概念,尤其在多核处理器和高并发应用中,理解并熟练掌握线程并发技术对于提升程序性能至关重要。在Java中,线程并发可以通过多种方式实现,包括继承Thread类、实现Runnable...

    java多线程查询数据库

    综上所述,"java多线程查询数据库"是一个涉及多线程技术、线程池管理、并发控制、分页查询等多个方面的复杂问题。通过理解和掌握这些知识点,我们可以有效地提高数据库操作的效率和系统的响应速度。

    java多线程并发

    ### Java多线程并发知识点详解 #### 一、Java多线程并发简介 在现代软件开发中,特别是在Java这样的主流编程语言中,多线程并发技术是提高程序执行效率、优化资源利用的关键手段之一。本篇文章将深入探讨Java中的...

    JAVA多线程并发编程

    但同时,多线程并发也会引入一些问题,如数据竞争和同步问题。 为了解决这些问题,Java提供了多种同步机制。`synchronized`关键字用于控制对共享资源的访问,确保同一时间只有一个线程可以执行特定代码块,从而避免...

    jdk1.5 线程并发与线程池的使用

    在Java编程语言中,线程并发和线程池是多任务执行的核心概念,尤其是在JDK 1.5及以后的版本中得到了显著增强。线程并发允许程序同时执行多个任务,提高了程序的效率和响应性。线程池是管理线程资源的有效方式,通过...

    Java中多线程的使用线程池.docx

    Java中的线程池是多线程编程中一种高效、可管理的执行机制。它通过预先创建并维护一组线程,避免了频繁地创建和销毁线程带来的开销,从而提高了程序的性能和响应速度。线程池的核心概念包括以下几个方面: 1. **...

    java多线程并发实战和源码

    Java多线程并发实战与源码分析是Java开发中至关重要的一部分,它涉及到程序性能优化、系统资源高效利用以及复杂逻辑的正确同步。本书主要聚焦于Java多线程的基础理论和实际应用,虽然书中实例和源码相对较少,但仍然...

    C#Winform异步多线程和线程池集成的用法

    本文将深入探讨如何在Winform应用中使用异步多线程和线程池。 一、线程基础 线程是操作系统分配CPU时间的基本单元,每个进程至少包含一个线程。在C#中,可以使用`System.Threading.Thread`类来创建和管理线程。通过...

    java多线程分页查询

    #### 二、Java多线程分页查询原理及实现 ##### 1. 分页查询基础概念 分页查询是指在查询数据时,将数据分成多个页面展示,而不是一次性返回所有数据。这种方式能够有效地减少单次查询的数据量,从而提高查询速度和...

    java多线程和并发.pdf

    Java多线程与并发编程是Java语言中用于处理多任务执行的关键技术,它能够帮助开发者设计出能够有效应对高并发请求的应用程序。在现代的线上(Online)和离线(Offline)应用中,合理利用多线程技术可以大幅提高系统...

    Java中的线程与线程池.pptx

    在多线程环境下,可以实现并行和并发执行。并行是指多个独立的任务同时运行,而并发则是在同一时间段内交替执行多个任务,通常在单个CPU核心上实现。在具有共享资源的并发场景中,线程安全和同步变得至关重要,以...

    Java多线程Executors批量执行数据实现限流

    Java多线程实现数据切割批量执行,实现限流操作。 java线程池Executors实现数据批量操作。 批量异步Executors处理数据,实现限流操作,QPS限流。 线程池调用第三方接口限流实现逻辑。 案例适合: 1.批量处理大数据。...

    java 多线程高并发相关资料收集

    本文将围绕“Java多线程高并发相关资料收集”这一主题,详细探讨这两个领域的核心知识点。 首先,多线程是指在单个程序中同时执行多个线程。Java提供了一个强大的多线程支持,允许开发者创建、管理和控制多个执行...

    java多线程处理数据库数据

    通过以上方法,我们可以在Java中有效地利用多线程处理数据库数据,提高程序的并发能力和效率。记得在设计时充分考虑线程间的协作与同步,以及数据库连接的管理和优化,以确保程序的稳定性和性能。

    Java并发编程相关源码集 包括多任务线程,线程池等.rar

     volatile关键字的非原子性、volatile关键字的使用、AtomicInteger原子性操作、线程安全小例子:多个线程竞争问题、多个线程多个锁问题、创建一个缓存的线程池、多线程使用Vector或者HashTable的示例(简单线程同步...

    JAVA使用线程池查询大批量数据

    线程池是一种多线程处理形式,预先创建了若干个线程,当有任务需要执行时,会从线程池中取出一个线程来执行任务,任务执行完毕后,线程返回线程池中等待新的任务。这种机制避免了频繁创建和销毁线程带来的性能开销,...

    多线程控制,线程池模式,HTTP线程

    在IT领域,多线程控制、线程池模式和HTTP线程是三个关键概念,尤其在高并发和高性能系统设计中扮演着重要角色。本文将深入探讨这些知识点,并结合实际应用进行阐述。 首先,让我们从多线程控制开始。多线程是指在一...

    轻量级java多线程池demo

    总之,"轻量级java多线程池demo"通过结合Java多线程和Actor模型,提供了一种高效、可扩展的并发解决方案。通过学习和实践这样的示例,开发者可以更好地理解和掌握Java并发编程的技巧,提升软件的性能和可维护性。...

    Java8并行流中自定义线程池操作示例

    Java8并行流中自定义线程池操作示例主要介绍了Java8并行流中自定义线程池操作,结合实例形式分析了并行流的相关概念、定义及自定义线程池的相关操作技巧。 1. 概览 Java8引入了流的概念,流是作为一种对数据执行...

Global site tag (gtag.js) - Google Analytics