`
jieke_ZJ
  • 浏览: 43191 次
  • 性别: 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多线程、并发及线程池介绍收藏的几篇文档

    里面是自己收藏的几篇关于线程的文档资料,大家可以看看哈

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

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

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

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

    java并发编程:juc线程池

    不了解并发编程和线程池的开发者可能会面临多线程竞争、死锁等问题。通过深入了解 Java 并发编程和 JUC 线程池,您可以更好地管理线程之间的协作和同步,充分发挥多核处理器的优势,确保程序稳定运行。 了解 Java ...

    java基础知识多线程线程池讲解和练习

    Java多线程和线程池是Java语言中非常重要的知识点,它们可以帮助我们更好地管理和控制程序的并发执行。本资源主要是对Java多线程和线程池进行详细的讲解和练习。

    线程池的多线程并发控制技术研究

    线程池的多线程并发控制技术研究.caj 线程池的多线程并发控制技术研究.caj 线程池的多线程并发控制技术研究.caj

    Java多线程编程总结

    Java线程:新特征-线程池 Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上) Java线程:新特征-锁(下) Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:...

    java多线程编程总结

    详细的讲述了多线程的各种用法 Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠...

    Java多线程读取大文本文件并批量插入MongoDB的实战代码

    Java多线程读取大文本文件并批量插入MongoDB的代码,文本文件,csv文件,可以结合POI改造使其支持excel。 适合做大量文本数据或日志文件入库的场景,大文本被拆分成多个线程处理,速度快。 批量插入MongoDB,存在则...

    java多线程视频教程(共七套)

    01、【中级原理】java多线程并发编程入门原理精通视频教程 02、【中级原理专题】java并发编程多线程高级专题课程 03. 【中级原理】高并发编程原理和线程池精通教程 04、【高级原理】Java并发多线程编程基础原理与...

    Java 利用多线程实现文件的分片下载

    刚学完多线程和线程池,以及线程爱好者。 使用场景及目标: 大文件的快速下载,经测试在100M带宽的网络下,下载一个40M的文件,不超过两秒钟,当然还得根据自己电脑的配置来讲。 其他说明: 文件如果特别小,而...

    Java多线程下载网络图片

    这个是关于Java多线程方面的技术,就是多个线程发送请求,从互联网上下载图片资源,通过这个案例可以知道Java中的多线程的基础知识

    JAVA线程、线程池资料----下载不扣分,回帖加1分,欢迎下载,童叟无欺

    在多线程大师Doug Lea的贡献下,在JDK1.5中加入了许多对并发特性的支持,例如:线程池。.......................................JAVA线程、线程池资料----下载不扣分,回帖加1分,欢迎下载,童叟无欺JAVA线程、...

    Java多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池)

    Java多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池)

    java多线程编程

    java多线程设计模式,附源码中文教程,java并发核心编程,JAVA线程池原理以及几种线程池类型介绍

    使用java的HttpClient实现多线程并发

    主要介绍了使用java的HttpClient实现多线程并发的相关资料,需要的朋友可以参考下

    JAVA高质量并发详解,多线程并发深入讲解

    本书全面解析了Java并发编程的核心概念、原理和实践,帮助读者深入理解多线程并发编程的精髓,提升编程能力和系统性能。 书中首先介绍了并发编程的基础知识,包括线程的基本概念、线程的生命周期、线程安全等问题。...

Global site tag (gtag.js) - Google Analytics